T09 · Insecure Skill Coding Practices
- Location
scripts/record.py:23- Finding
Path Traversal in Record Date Parameters Enables JSON File Access Outside the Records Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/record.py:23-52, with affected command-line parameters atscripts/record.py:831-887
Vulnerability Type: Path traversal and unrestricted file access
Risk Level: HighVulnerable Code
python def load_day(date_str): path = os.path.join(RECORDS_DIR, f"{date_str}.json") if os.path.exists(path): with open(path, "r", encoding="utf-8") as f: return json.load(f) return { "date": date_str, "weight_kg": None, "meals": {"breakfast": [], "lunch": [], "dinner": [], "snack": []}, "water_ml": 0, "water_target_ml": 2000, "exercises": [], "daily_summary": { "total_calories_in": 0, "total_calories_out": 0, "total_protein_g": 0, "total_carbs_g": 0, "total_fat_g": 0, "total_water_ml": 0, }, } def save_day(record): os.makedirs(RECORDS_DIR, exist_ok=True) path = os.path.join(RECORDS_DIR, f"{record['date']}.json") recalc_summary(record) with open(path, "w", encoding="utf-8") as f: json.dump(record, f, ensure_ascii=False, indent=2) return recordRepresentative affected argument definitions:
python p_w.add_argument("--date", required=True) p_m.add_argument("--date", required=True) p_wa.add_argument("--date", required=True) p_e.add_argument("--date", required=True) p_u.add_argument("--date", required=True) p_t.add_argument("--date", required=True) p_a.add_argument("--date", required=True)A similar construction exists in
scripts/chart.py:149:python path = os.path.join(RECORDS_DIR, f"{date_str}.json")Technical Analysis
The
--datevalue is accepted as an unrestricted string and interpolated directly into a filesystem path.os.path.join()does not remove parent-directory components such as ...[truncated 1633 chars]- Remediation
View remediation
Remediation Suggestions
-
Parse every date before any filesystem operation:
python from datetime import datetime def validate_date(value): parsed = datetime.strptime(value, "%Y-%m-%d") canonical = parsed.strftime("%Y-%m-%d") if value != canonical: raise ValueError("Date must use canonical YYYY-MM-DD format") return canonical -
Resolve the final path and enforce containment:
python def record_path(date_str): safe_date = validate_date(date_str) base = os.path.realpath(RECORDS_DIR) path = os.path.realpath(os.path.join(base, safe_date + ".json")) if os.path.commonpath([base, path]) != base: raise ValueError("Record path escapes the records directory") return path -
Use this single path-construction function in
load_day(),save_day(), reporting functions, and chart functions. -
Add parser-level validation with an
argparsetype function so malformed values are rejected before command dispatch. -
Write records atomically through a temporary file inside
RECORDS_DIR, then replace the destination. -
Add regression tests for
../, absolute paths, alternate separators, malformed dates, and canonical valid dates.
-
