T09 · Insecure Skill Coding Practices
- Location
nex-meetcost.py:237- Finding
Arbitrary User-Writable File Overwrite Through Export Path Traversal
- Content
View full analysis
Vulnerability Details
File Location:
nex-meetcost.py, lines 237–241
Vulnerability Type: Unrestricted file path and path traversal
Risk Level: MediumVulnerable Code:
python output_file = args.output or f"meetcost_export.{args.format}" output_path = EXPORT_DIR / output_file with open(output_path, 'w', encoding='utf-8') as f: f.write(data)Technical Analysis
The user-controlled
--outputvalue is joined toEXPORT_DIRwithout checking whether it is an absolute path or contains traversal components such as...In
pathlib, joining a base path with an absolute path discards the base path. Relative paths containing../can similarly escape the intended export directory. The destination is then opened in write mode, which creates a missing file or truncates an existing file.The command therefore provides an unrestricted file-write primitive for any path writable by the current operating-system user. Exported data also contains attacker-influenced meeting fields, allowing some control over the written content, although the output must conform to the generated JSON or CSV structure.
Attack Path
- The attacker persuades a user or automation agent to run an export command with a malicious
--outputvalue. - The supplied path is absolute or traverses outside the export directory, for example:
bash nex-meetcost export json --output ../../target-file EXPORT_DIR / output_fileresolves outside the intended~/.nex-meetcost/exportsdirectory.open(output_path, 'w')truncates or creates the destination.- The generated export data is written to that destination.
Symlinks placed within the export directory can provide another overwrite route because the code does not check the resolved destination or reject symbolic-link targets.
Impact Assessment
An attacker can overwrite or corrupt files writable by the user running the command. Pote ...[truncated 409 chars]
- The attacker persuades a user or automation agent to run an export command with a malicious
- Remediation
View remediation
Remediation Suggestions
Restrict all exports to the designated export directory:
- Reject absolute output paths.
- Resolve both the export directory and requested destination with
Path.resolve(). - verify that the resolved destination is a child of the resolved export directory by using
Path.relative_to()orPath.is_relative_to()where supported. - Reject
..path components and consider accepting only a filename rather than a path. - Reject symbolic-link destinations or open files using platform-appropriate no-follow protections.
- Avoid silently truncating existing files. Use exclusive creation mode (
'x') by default or require explicit overwrite confirmation. - Consider enforcing the extension corresponding to the selected export format.
Example validation pattern:
python output_file = Path(args.output or f"meetcost_export.{args.format}") if output_file.is_absolute() or ".." in output_file.parts: raise ValueError("Output must be a filename inside the export directory") export_root = EXPORT_DIR.resolve() output_path = (export_root / output_file).resolve() try: output_path.relative_to(export_root) except ValueError: raise ValueError("Output path escapes the export directory") with open(output_path, "x", encoding="utf-8") as f: f.write(data)
