T09 · Insecure Skill Coding Practices
- Location
personanexus_skill/cli.py:43- Finding
Predictable Temporary File Allows Symlink-Based File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
personanexus_skill/cli.py, lines 43-59
Vulnerability Type: Predictable temporary file and symlink-following file write
Risk Level: MediumVulnerable Code
python def _atomic_write(path: Path, content: str) -> None: """Write content to a file atomically via temp-and-rename. On POSIX systems ``os.replace`` is atomic within the same filesystem, preventing partial writes from corrupting the target file. """ tmp = path.with_suffix(path.suffix + ".tmp") try: tmp.write_text(content, encoding="utf-8") os.replace(str(tmp), str(path)) except BaseException: tmp.unlink(missing_ok=True) raiseTechnical Analysis
The temporary file name is deterministically derived from the destination by appending
.tmp. The application neither creates this file exclusively nor verifies that it is a regular file rather than a symbolic link.In a directory writable by another local user or process, an attacker can create the predictable temporary path as a symbolic link to another file.
Path.write_text()follows symbolic links, so the content is written to the link target using the privileges of the user running PersonaNexus.Although
os.replace()makes the final rename atomic, it does not protect the preceding write. After the linked target has been overwritten, the rename only replaces the requested destination with the symlink itself.This helper is used by the
compileandinitCLI operations, making the issue reachable whenever output is written into an attacker-accessible directory.Attack Path
- A victim plans to compile an identity to
/shared/result.md. - The attacker has write access to
/sharedand predicts that the temporary path will be/shared/result.md.tmp. - The attacker creates a symbolic link:
bash ln -s /home/victim/.config/example.conf /shared/result.md.tmp - The victim runs:
bash python -m pe
...[truncated 997 chars]
- A victim plans to compile an identity to
- Remediation
View remediation
Remediation Suggestions
Create an unpredictable temporary file securely and exclusively in the destination directory:
- Use
tempfile.NamedTemporaryFile()ortempfile.mkstemp()withdir=path.parent. - Ensure exclusive creation so an existing path cannot be reused.
- Do not follow symbolic links. Where available, use
O_NOFOLLOWwithos.open(). - Apply restrictive permissions such as
0o600. - Flush buffered data and call
os.fsync()before replacement. - Replace the destination with
os.replace()only after the temporary file is safely closed. - Clean up the unique temporary file on failure.
For example:
python import os import tempfile from pathlib import Path def _atomic_write(path: Path, content: str) -> None: path = path.resolve() fd, tmp_name = tempfile.mkstemp( prefix=f".{path.name}.", suffix=".tmp", dir=path.parent, text=True, ) tmp_path = Path(tmp_name) try: with os.fdopen(fd, "w", encoding="utf-8") as stream: stream.write(content) stream.flush() os.fsync(stream.fileno()) os.replace(tmp_path, path) except BaseException: tmp_path.unlink(missing_ok=True) raiseIf output directories may be shared, additionally verify directory ownership and permissions before writing.
- Use
