T09 · Insecure Skill Coding Practices
- Location
scripts/log-meal.py:12- Finding
Path Traversal Allows Arbitrary JSON File Creation or Overwrite Through Meal Logging
- Content
View full analysis
Vulnerability Details
File Location:
scripts/log-meal.py, lines 12-28
Vulnerability Type: Path traversal and unrestricted file write
Risk Level: HighVulnerable Code
python def get_log_path(date): """Get path to daily log file""" base = Path.home() / '.openclaw' / 'workspace' / 'fitness' / 'logs' base.mkdir(parents=True, exist_ok=True) return base / f"{date}.json" def load_log(date): """Load existing log or create new""" path = get_log_path(date) if path.exists(): with open(path) as f: return json.load(f) return {"date": date, "workouts": [], "meals": []} def save_log(date, data): """Save log to file""" path = get_log_path(date) with open(path, 'w') as f: json.dump(data, f, indent=2)Technical Analysis
The required
--dateargument is documented as a date inYYYY-MM-DDformat, but the application does not validate or canonicalize it. It is interpolated directly into a filename and joined to the intended log directory.A value containing traversal components such as
../../can escape the log directory. If the resulting component is absolute,pathlibcan also discard the preceding base path. The resulting path is then opened in write mode without verifying that its resolved location remains under the fitness log directory.When the target does not exist,
load_log()creates a default record in memory andsave_log()creates the attacker-selected.jsonfile. When it exists and contains a compatible JSON structure, the script appends a meal and overwrites the file. Symbolic links are followed as well, creating an additional route to unintended files.Attack Path
- An attacker, untrusted caller, or manipulated agent invokes
log-meal.py. - The caller supplies a crafted
--datecontaining directory traversal components, such as../../../../../../tmp/target. - `get_log_path( ...[truncated 924 chars]
- An attacker, untrusted caller, or manipulated agent invokes
- Remediation
View remediation
Remediation Suggestions
- Parse the argument strictly with
datetime.strptime(value, "%Y-%m-%d"). - Regenerate the filename from the parsed date rather than retaining the original input.
- Reject absolute paths, path separators, traversal components, and non-date values.
- Resolve both the base directory and destination, then verify that the destination is a child of the base directory.
- Reject symbolic-link destinations where feasible.
- Use atomic writes through a securely created temporary file in the same directory, followed by
os.replace(). - Apply restrictive file permissions because meal logs may contain health-related information.
Example validation pattern:
python from datetime import datetime def get_log_path(date_text): parsed = datetime.strptime(date_text, "%Y-%m-%d").date() base = ( Path.home() / ".openclaw" / "workspace" / "fitness" / "logs" ).resolve() base.mkdir(parents=True, exist_ok=True) destination = (base / f"{parsed.isoformat()}.json").resolve() if destination.parent != base: raise ValueError("Invalid log path") return destination- Parse the argument strictly with
