T09 · Insecure Skill Coding Practices
- Location
scripts/book.sh:17- Finding
Financial records are created without restrictive filesystem permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/book.sh:17-43andscripts/book.sh:233-241
Vulnerability Type: Sensitive local data exposure through process-default permissions
Risk Level: MediumVulnerable Code
python def ensure_data_dir(): if not os.path.exists(DATA_DIR): os.makedirs(DATA_DIR) def load_records(): ensure_data_dir() if os.path.exists(RECORDS_FILE): with open(RECORDS_FILE, 'r') as f: return json.load(f) return [] def save_records(records): ensure_data_dir() with open(RECORDS_FILE, 'w') as f: json.dump(records, f, ensure_ascii=False, indent=2) def load_budgets(): ensure_data_dir() if os.path.exists(BUDGETS_FILE): with open(BUDGETS_FILE, 'r') as f: return json.load(f) return {} def save_budgets(budgets): ensure_data_dir() with open(BUDGETS_FILE, 'w') as f: json.dump(budgets, f, ensure_ascii=False, indent=2)python def save_goals(goals): ensure_data_dir() goals_file = os.path.join(DATA_DIR, "goals.json") with open(goals_file, 'w') as f: json.dump(goals, f, ensure_ascii=False, indent=2)Technical Analysis
The application stores personal financial information in
~/.bookkeeping, including transaction amounts, income and expense categories, free-form transaction notes, budgets, and savings goals. Neitheros.makedirs()nor the calls toopen(..., 'w')specify or enforce restrictive permissions.Consequently, permissions depend on the process umask. With a common umask of
022, a newly created directory may receive mode0755, while files may receive mode0644. If the user's home directory is traversable by other accounts, or if the data directory is otherwise exposed through shared storage, these permissions allow other local users to read the financial data.Existing files are also not checked ...[truncated 1356 chars]
- Remediation
View remediation
Remediation Suggestions
- Set a restrictive process umask, such as
0o077, before creating bookkeeping data. - Create
~/.bookkeepingwith mode0700. - Create all financial data files with mode
0600. - Check and repair permissions on existing directories and files.
- Use atomic writes through a temporary file in the same protected directory, followed by
os.replace(), to avoid partial or corrupted JSON files. - Reject symbolic links or unexpected non-regular files before writing sensitive data.
Example hardening approach:
python import os import stat import tempfile os.umask(0o077) def ensure_data_dir(): os.makedirs(DATA_DIR, mode=0o700, exist_ok=True) os.chmod(DATA_DIR, 0o700) def secure_json_write(path, value): ensure_data_dir() if os.path.lexists(path) and not stat.S_ISREG(os.lstat(path).st_mode): raise RuntimeError("Refusing to overwrite a non-regular data file") fd, temporary_path = tempfile.mkstemp(dir=DATA_DIR) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w") as output: json.dump(value, output, ensure_ascii=False, indent=2) output.flush() os.fsync(output.fileno()) os.replace(temporary_path, path) os.chmod(path, 0o600) except Exception: try: os.unlink(temporary_path) except FileNotFoundError: pass raise- Set a restrictive process umask, such as
