T09 · Insecure Skill Coding Practices
- Location
camsnap.py:22- Finding
Unrestricted Output Path Allows Arbitrary Image File Writes
- Content
View full analysis
Vulnerability Details
File Location:
camsnap.py, lines 22–28 and 50–53
Vulnerability Type: Improper path restriction and arbitrary file write
Risk Level: MediumVulnerable Code:
python def _validate_output_path(path: str) -> Path: """Validate and normalize an output path, guarding against traversal and bad extensions.""" resolved = Path(path).resolve() ext = resolved.suffix.lower() if ext and ext not in _ALLOWED_EXTENSIONS: raise ValueError(f"Unsupported image extension: {ext!r}. Allowed: {sorted(_ALLOWED_EXTENSIONS)}") return resolvedpython if output_path: dest = _validate_output_path(output_path) dest.parent.mkdir(parents=True, exist_ok=True)The resulting destination is subsequently passed to:
python success = cv2.imwrite(str(dest), frame)Technical Analysis
_validate_output_path()canonicalizes the supplied path withPath.resolve(), but canonicalization does not enforce a filesystem boundary. There is no trusted root directory against which the resolved destination is checked.Consequently, absolute paths and relative traversal paths such as
../../outside/snapshot.jpgare accepted as long as their suffix is in the image-extension allowlist. The extension check does not prevent writing outside the intended snapshot directory. In addition,dest.parent.mkdir(parents=True, exist_ok=True)creates attacker-selected parent directories before the image is written.This behavior contradicts the documented path-traversal protection. Exploitation requires control over the positional
output_pathargument or equivalent access to the module API.Attack Path
- An attacker or untrusted caller supplies an absolute destination or a traversal path, such as
../../target/location/image.jpg. _validate_output_path()resolves the input to an absolute path.- The function validates only the filename extension ...[truncated 909 chars]
- An attacker or untrusted caller supplies an absolute destination or a traversal path, such as
- Remediation
View remediation
Remediation Suggestions
Define an explicit trusted output root and require every destination to remain within it after canonicalization. Reject absolute user paths and any relative path that escapes the root. Perform validation before creating directories or writing files.
For example:
python def _validate_output_path(path: str, output_dir: str) -> Path: root = Path(output_dir).resolve(strict=False) supplied = Path(path) if supplied.is_absolute(): raise ValueError("Absolute output paths are not allowed") dest = (root / supplied).resolve(strict=False) if not dest.is_relative_to(root): raise ValueError("Output path escapes the permitted directory") if dest.suffix.lower() not in _ALLOWED_EXTENSIONS: raise ValueError("Unsupported image extension") return destAdditional hardening should include:
- Apply the same trusted-root policy consistently to CLI and module callers.
- Require a valid extension rather than permitting an empty suffix.
- Refuse to overwrite existing files unless overwrite behavior is explicitly requested.
- Consider rejecting symlinked parent components or opening output files with exclusive creation semantics where feasible.
- Create directories only after all containment and file-type checks succeed.
- Add tests for absolute paths,
..traversal, nested traversal, symlink escapes, unsupported or missing extensions, and existing destinations.
