T09 · Insecure Skill Coding Practices
Warning
- Location
- expense_tracker.py:16
- Finding
- Sensitive Financial Records Stored in Plaintext Without Enforced Access Restrictions## Vulnerability Details **File Location**: `expense_tracker.py`, lines 16–42 **Vulnerability Type**: Plaintext storage of sensitive data with ambient filesystem permissions **Risk Level**: Medium ### Vulnerable Code ```python # 数据目录 DATA_DIR = Path.home() / ".openclaw" / "skills-data" / "family-expense-intent" PROFILES_FILE = DATA_DIR / "profiles.json" CONVERSATIONS_FILE = DATA_DIR / "conversations.json" INCOME_FILE = DATA_DIR / "income.json" PATTERNS_FILE = DATA_DIR / "patterns.json" BUDGETS_FILE = DATA_DIR / "budgets.json" GOALS_FILE = DATA_DIR / "goals.json" SUBSCRIPTIONS_FILE = DATA_DIR / "subscriptions.json" def ensure_data_dir(): """确保数据目录存在""" DATA_DIR.mkdir(parents=True, exist_ok=True) files = { PROFILES_FILE: {"members": {}, "default_member": None}, CONVERSATIONS_FILE: {"conversations": []}, INCOME_FILE: {"income": []}, PATTERNS_FILE: {"patterns": {}, "insights": []}, BUDGETS_FILE: {"budgets": {}, "monthly_total": 10000}, GOALS_FILE: {"goals": []}, SUBSCRIPTIONS_FILE: {"subscriptions": []}, } for f, default in files.items(): if not f.exists(): with open(f, 'w', encoding='utf-8') as fp: json.dump(default, fp, ensure_ascii=False, indent=2) ``` ### Technical Analysis The application persists household profiles, free-form expense descriptions, income, budgets, savings goals, and subscription records as unencrypted JSON files. The data directory is created without an explicit owner-only mode, and files are opened without explicitly enforcing mode `0600`. Their effective permissions therefore depend on the process umask and permissions inherited from parent directories. On a system with a permissive umask or shared access to the user's data hierarchy, another local user or process may be able to read these records. The application also does not inspect or repair ...[truncated 1788 chars]
- Remediation
- ## Remediation Suggestions 1. Create the data directory with owner-only permissions and repair existing permissions: ```python DATA_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) os.chmod(DATA_DIR, 0o700) ``` 2. Create new data files with mode `0600`, preferably through `os.open` so permissions are specified atomically: ```python fd = os.open(file_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as fp: json.dump(data, fp, ensure_ascii=False, indent=2) ``` 3. Validate and correct permissions on every existing JSON file during initialization: ```python os.chmod(file_path, 0o600) ``` 4. Use atomic writes through a temporary file in the protected data directory, set that file to mode `0600`, flush and synchronize it, and then replace the destination with `os.replace`. 5. Consider authenticated encryption at rest for financial records when the deployment threat model includes local account compromise, shared storage, backups, or device theft. Store encryption keys through an operating-system credential facility rather than beside the encrypted files. 6. Avoid broadly suppressing file-access and JSON errors. Report permission failures safely so users know when secure storage initialization or permission repair did not succeed.
