T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/policy_check.py:154- Finding
Scan-Root Escape Through Symbolic Links
- Content
View full analysis
bool: if not path.is_file(): return False if path.stat().st_size > 1024 * 1024: return False if path.suffix.lower() in TEXT_EXTENSIONS: return True if path.name in {"Dockerfile", "Makefile"}: return True return path.suffix == "" def iter_files(target: Path) -> Iterable[Path]: if target.is_file(): if should_scan_file(target): yield target return for root, dirs, files in os.walk(target): dirs[:] = [d for d in dirs if d not in DEFAULT_IGNORE_DIRS] root_path = Path(root) for filename in files: candidate = root_path / filename if should_scan_file(candidate): yield candidate ``` The resulting path is subsequently read without a containment check: ```python def scan_file(path: Path, root: Path) -> List[Dict[str, object]]: findings: List[Dict[str, object]] = [] try: text = path.read_text(encoding="utf-8", errors="ignore") except OSError: return findings ``` ### Technical Analysis `Path.is_file()`, `Path.stat()`, and `Path.read_text()` follow symbolic links. The scanner does not reject symbolic links or resolve each candidate and verify that the resolved path remains beneath the requested scan root. Consequently, an untrusted repository can contain a file symlink whose name has a permitted text extension but whose target is outside the repository. The scanner will treat the symlink as an ordinary file and read the external target. This exceeds the least privilege required for the declared repository-scanning functionality: scanning a selected repository does not require access to arbitrary files elsewhere on the host. ### A ...[truncated 1361 chars]- Remediation
View remediation
