T09 · Insecure Skill Coding Practices
- Location
scripts/generate_cli_reference.py:8- Finding
CLI Reference Generator Writes Outside the Project Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_cli_reference.py, lines 8–9 and 151
Vulnerability Type: Unsafe output path resolution and potential symlink-assisted file overwrite
Risk Level: MediumVulnerable Code
python REPO_ROOT = Path(__file__).resolve().parents[3] HUMAN_REF = REPO_ROOT / "docs" / "cli-reference.md"python HUMAN_REF.write_text(content)Technical Analysis
The generator calculates the repository root using
Path(__file__).resolve().parents[3]. From the project pathartifact/scripts/generate_cli_reference.py, this resolves several levels aboveartifact, rather than to the project root.In the audited directory layout, the resulting destination is
/tmp/docs/cli-reference.md, while the intended project documentation is stored atreferences/cli-reference.md. Consequently, running the generator modifies a file outside the project boundary.The call to
Path.write_text()also follows symbolic links. If another local user or process can prepare the incorrectly resolved output path, the generated content can be redirected through a symbolic link. The destination remains constrained by the invoking process's filesystem permissions, but execution under a more privileged account could increase the overwrite scope.Attack Path
- An attacker determines that the generator writes to the incorrectly resolved external path.
- Where filesystem permissions allow, the attacker creates the external
docsdirectory and makescli-reference.mda symbolic link to another file writable by the account expected to run the generator. - A user or automation process invokes
scripts/generate_cli_reference.sh. - The shell script executes
scripts/generate_cli_reference.py. - The Python script resolves
HUMAN_REFoutside the project and callswrite_text(content). - The unrelated external file, or the writable destination of the symbolic link, is overwritten with generated CLI documentation.
...[truncated 523 chars]
- Remediation
View remediation
Remediation Suggestions
- Resolve the project root from the script directory using the correct ancestor:
python PROJECT_ROOT = Path(__file__).resolve().parents[1] HUMAN_REF = PROJECT_ROOT / "references" / "cli-reference.md"- Verify that the resolved output remains inside the project before writing:
python PROJECT_ROOT = Path(__file__).resolve().parents[1] HUMAN_REF = PROJECT_ROOT / "references" / "cli-reference.md" resolved_parent = HUMAN_REF.parent.resolve() if PROJECT_ROOT not in (resolved_parent, *resolved_parent.parents): raise RuntimeError("Output path escapes the project directory")-
Reject symbolic-link output files before replacement and ensure the destination directory is trusted.
-
Write to a securely created temporary file in the same trusted directory, then atomically replace the destination after validation.
-
Add an automated test asserting that the generated destination equals the expected project-relative path and cannot resolve outside the project root.
-
Run the documentation generator with the minimum filesystem privileges required and never invoke it as an administrative user without a specific need.
