T09 · Insecure Skill Coding Practices
- Location
receipt_snap.py:122- Finding
Financial receipt metadata is stored in a plaintext CSV without restrictive permissions
- Content
View full analysis
Vulnerability Details
File Location:
receipt_snap.py, lines 122–136
Vulnerability Type: Plaintext storage of sensitive financial data with ambient filesystem permissions
Risk Level: Mediumpython def append_to_log(row_data): """Append row to local CSV log""" import csv as csv_module log_dir = os.path.dirname(LOG_FILE) if log_dir: os.makedirs(log_dir, exist_ok=True) header = ["Date", "Vendor", "Description", "Original Amount", "Currency", "EUR Amount", "Exchange Rate", "Category", "Drive Link", "Notes"] write_header = not os.path.exists(LOG_FILE) with open(LOG_FILE, 'a', newline='', encoding='utf-8') as f: writer = csv_module.writer(f) if write_header: writer.writerow(header) writer.writerow([str(x) for x in row_data])Technical Analysis
The function writes receipt information to an unencrypted local CSV file. The stored fields include vendor names, descriptions, original and converted amounts, expense categories, Google Drive links, and free-form notes. This is sensitive financial and business information.
The file is created using Python's standard
open()operation without explicitly setting owner-only permissions. Its effective permissions therefore depend on the process umask. On systems with a typical022umask, a newly created file may be readable by other local users. The function also does not inspect or correct the permissions of an existing log file.The configured path is accepted without validating that the destination is a regular file rather than a symbolic link. Although exploitation depends on local filesystem access and directory permissions, this omission further weakens the safety of sensitive-data storage.
Attack Path
- The user processes a receipt with
receipt_snap.py process. cmd_process()constructs a row containing financial metadata and callsappend_to_log().append_to_log()creates or appends t ...[truncated 1024 chars]
- The user processes a receipt with
- Remediation
View remediation
Remediation Suggestions
- Create new log files atomically with owner-only permissions such as
0600, rather than relying on the process umask. - Before appending, use
os.lstat()to verify that the destination is a regular file and not a symbolic link. - Check existing file permissions and reject or correct files readable or writable by group or other users.
- Create the containing directory with restrictive permissions such as
0700. - Consider encrypting the local backup or making local CSV persistence opt-in because the same information is already sent to the configured Google Sheet.
- Document data retention, secure deletion, backup handling, and access-control expectations for the receipt log.
A hardened implementation can use
os.open()withos.O_CREAT | os.O_APPEND | os.O_WRONLYand mode0o600, then wrap the descriptor withos.fdopen(). Existing files should still be validated before use.- Create new log files atomically with owner-only permissions such as
