T09 · Insecure Skill Coding Practices
- Location
scripts/init.py:84- Finding
Arbitrary File Deletion Through CASHBOOK_DB and Forced Initialization
- Content
View full analysis
Vulnerability Details
File Location:
scripts/init.py:84-89, with attacker-controlled path resolution inscripts/db.py:9-12
Vulnerability Type: Arbitrary file deletion
Risk Level: HighTechnical Analysis
The database path is accepted directly from the
CASHBOOK_DBenvironment variable without restriction, canonicalization, ownership validation, or verification that the target is a cashbook SQLite database:python def get_db_path(): """Return the database path, preferring CASHBOOK_DB.""" return os.environ.get("CASHBOOK_DB", os.path.expanduser("~/.local/share/cashbook/cashbook.db"))Forced initialization deletes whatever filesystem object exists at that path before attempting to create a database:
python def init_db(force=False): db_path = get_db_path() if force and os.path.exists(db_path): os.remove(db_path) print(f"Deleted old database: {db_path}")The
--forceoption is exposed without an interactive confirmation or a check that the path is within the normal cashbook data directory:python def main(): parser = argparse.ArgumentParser(description="Initialize cashbook database") parser.add_argument("--force", action="store_true", help="Delete and recreate database") args = parser.parse_args() init_db(force=args.force)Consequently, any actor able to influence the environment and cause the initialization command to run with
--forcecan select an arbitrary file writable by the process and delete it. The deletion occurs before SQLite validates the target, so the file does not need to be a database.This is especially relevant in an agent environment, where tool instructions or user-supplied command parameters may influence environment variables and command invocation.
Attack Path
- The attacker identifies a file writable by the user running the skill, such as a document ...[truncated 1266 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not pass the unrestricted
CASHBOOK_DBvalue directly to a destructive operation. - Resolve the path with
os.path.realpath()and, by default, require it to remain under a dedicated directory such as~/.local/share/cashbook/. - If custom database paths must be supported, separate database selection from database deletion. Require an explicit, independently supplied confirmation of the canonical path.
- Before deletion, verify that the target is a regular file, is not a symbolic link, is owned by the current user, contains a valid SQLite header, and has the expected cashbook schema or application marker.
- Refuse special files, directories, and paths outside an approved storage boundary.
- Create a timestamped backup before resetting an existing database.
- Require interactive confirmation unless a separately protected administrative automation mode is explicitly enabled.
- Prefer clearing known cashbook tables inside a validated database rather than deleting an arbitrary path.
- Do not pass the unrestricted
