T09 · Insecure Skill Coding Practices
- Location
scripts/workout.py:61- Finding
Sensitive Health Data Stored Without Enforced Restrictive File Permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/workout.py:61-63
Vulnerability Type: Plaintext sensitive-data storage with insufficient file-permission enforcement
Risk Level: MediumVulnerable Code
python def save_json(path, data): with open(path, "w") as f: json.dump(data, f, ensure_ascii=False, indent=2)Sensitive workout and health data is passed to this function at locations including:
python save_json(HISTORY_FILE, hist_data)python save_json(BODY_FILE, data)Technical Analysis
The application stores personal health information in
data/history.jsonanddata/body_status.json. This can include injuries, menstrual status, sleep condition, height, weight, body-fat percentage, physical limitations, goals, and free-form notes.save_json()creates or overwrites these files using Python's defaultopen(path, "w")behavior. It does not explicitly set a restrictive mode such as0600, so newly created file permissions depend on the process umask. It also does not correct insecure permissions on existing files. On a shared host or under a permissive umask, another local account or process may be able to read this sensitive information.The data is also stored as plaintext. The principal confirmed weakness is the lack of enforced filesystem access controls; encryption at rest may additionally be appropriate depending on the deployment threat model.
Attack Path
- A user records body measurements or a sensitive status through the skill.
- The relevant command passes the resulting object to
save_json(). save_json()creates or overwriteshistory.jsonorbody_status.jsonwithout explicitly restricting its permissions.- If the runtime umask or pre-existing permissions allow access, another local user or process reads the JSON file directly.
- The attacker obtains the stored health, fitness, and free-form note data.
Exploitation ...[truncated 629 chars]
- Remediation
View remediation
Remediation Suggestions
- Create the
data/directory with mode0700and verify its permissions during initialization. - Create sensitive JSON files with mode
0600, usingos.open()with explicit flags and permissions rather than relying on the ambient umask. - Apply
os.chmod(path, 0o600)to existing sensitive files before or after replacement so legacy permissions are corrected. - Write updates atomically to a temporary file in the protected directory, set mode
0600, flush and synchronize the file, and then replace the destination withos.replace(). - Consider encryption at rest when local administrators, backups, or storage-layer actors are part of the threat model.
- Document what health data is retained and provide secure deletion and retention controls.
Example hardened approach:
python import json import os import tempfile def save_json(path, data): directory = os.path.dirname(path) os.makedirs(directory, mode=0o700, exist_ok=True) os.chmod(directory, 0o700) fd, temporary_path = tempfile.mkstemp(dir=directory) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) f.flush() os.fsync(f.fileno()) os.replace(temporary_path, path) os.chmod(path, 0o600) except Exception: try: os.unlink(temporary_path) except FileNotFoundError: pass raise- Create the
