T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/vet.py:98- Finding
Symbolic-Link Traversal Allows Reading Files Outside the Audited Skill
- Content
View full analysis
Vulnerability Details
File Location:
scripts/vet.py:98-106
Vulnerability Type: Symbolic-link traversal and unauthorized local file access
Risk Level: MediumVulnerable Code
python def _scan_files(self): for filepath in self.skill_path.rglob("*"): if filepath.is_dir(): continue if filepath.suffix in ('.pyc', '.pyo', '.so', '.dll', '.exe'): self.findings.append(Finding("danger", "binary", f"Binary file found: {filepath.name}", str(filepath), 0, 25)) continue try: content = filepath.read_text(encoding="utf-8", errors="ignore") except Exception: continueTechnical Analysis
The scanner treats the audited Skill directory as untrusted input but does not reject symbolic links or verify that each resolved file remains inside
self.skill_path.Path.read_text()follows a symbolic link when it points to a readable file.An attacker can therefore package a symbolic link whose apparent location is inside the Skill but whose target is an arbitrary file available to the user running the audit. The target's contents are then loaded and inspected by the scanner.
This behavior violates least privilege because auditing a Skill only requires access to files physically contained within that Skill. The scanner should not follow references into unrelated portions of the local filesystem.
Attack Path
- An attacker creates a Skill directory containing a symbolic link, such as
linked-secret, that points to a likely sensitive local path. - The victim obtains the untrusted Skill and runs
python3 scripts/vet.py --skill /path/to/skill. rglob("*")discovers the symbolic link as an entry in the audited directory.- The scanner does not reject the link or validate its resolved destination.
filepath.read_text()follows the link and reads the external file.- The external contents are ...[truncated 647 chars]
- An attacker creates a Skill directory containing a symbolic link, such as
- Remediation
View remediation
Remediation Suggestions
-
Reject symbolic links before reading any entry:
python if filepath.is_symlink(): self.findings.append(Finding( "warn", "symlink", "Symbolic links are not scanned", str(filepath.relative_to(self.skill_path)), 0, 0 )) continue -
Resolve the audit root once and confirm that every candidate's resolved path remains beneath it:
python root = self.skill_path.resolve() try: resolved = filepath.resolve(strict=True) resolved.relative_to(root) except (FileNotFoundError, RuntimeError, ValueError): continue -
Perform containment validation immediately before opening the file to reduce time-of-check/time-of-use exposure.
-
Open files using directory-relative, no-follow operating-system primitives where supported, such as
os.open()withO_NOFOLLOW. -
Apply the same policy to file-size calculation and any future archive or dependency inspection logic.
-
