T09 · Insecure Skill Coding Practices
- Location
scripts/report_generator_patch.py:56- Finding
Predictable Temporary File Permits Symlink-Based Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/report_generator_patch.py, lines 56–64
Vulnerability Type: Predictable temporary file and symlink race
Risk Level: MediumVulnerable Code
python destination.parent.mkdir(parents=True, exist_ok=True) temporary = destination.with_name(f".{destination.name}.tmp") if temporary.exists(): raise FileExistsError(f"Temporary path already exists: {temporary}") try: temporary.write_text(content, encoding="utf-8", newline="\n") if destination.exists() and overwrite: destination.unlink()Technical Analysis
The temporary filename is deterministically derived from the destination filename. The code first checks whether that path exists and later opens it through
Path.write_text(). These operations are not atomic.An attacker with write access to the destination directory can create a symbolic link at the predictable temporary pathname after the existence check but before
write_text()opens it. Because ordinary file opening follows symbolic links, the linked target will be truncated and replaced with report content.This is a time-of-check/time-of-use vulnerability. Checking
temporary.exists()does not securely reserve the pathname or prevent it from being replaced before use.Attack Path
- A user approves a report destination such as
/shared/report.html. - The function derives the temporary path
/shared/.report.html.tmp. - The function verifies that the temporary path does not currently exist.
- A local attacker with write access to
/sharedcreates/shared/.report.html.tmpas a symbolic link to another file writable by the Skill process. temporary.write_text()follows the symbolic link.- The linked file is truncated and overwritten with the generated HTML.
- The attacker may repeat the race against future report-generation operations.
Successful exploitation requires the attacker to modify ...[truncated 666 chars]
- A user approves a report destination such as
- Remediation
View remediation
Remediation Suggestions
- Create the temporary file atomically inside the destination directory using
tempfile.NamedTemporaryFile(delete=False, dir=destination.parent)oros.open()withO_CREAT | O_EXCL. - Use
O_NOFOLLOWwhere supported so that opening a symbolic link fails. - Write through the securely obtained file descriptor rather than reopening a pathname.
- Flush and optionally call
os.fsync()before atomically installing the completed file. - Verify that the temporary object is a regular file owned by the current process.
- Prefer output directories that are not writable by untrusted local users.
- Remove temporary files by file descriptor or securely retained randomized pathname during error handling.
- Create the temporary file atomically inside the destination directory using
