{"record":{"id":"df888de5164fb3af","repo":"abhigyanpatwari/GitNexus","slug":"results-directory-must-not-traverse-symlinks-roo","errorCode":null,"errorMessage":"results directory must not traverse symlinks: {root}","messagePattern":"results directory must not traverse symlinks: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/evolve.py","lineNumber":297,"sourceCode":"    mode = path.lstat().st_mode\n    if path.is_symlink() or not stat.S_ISREG(mode):\n        raise SandboxError(f\"evidence source must be a regular non-symlink file: {path}\")\n    with path.open(\"rb\") as handle:\n        if path.stat().st_size > limit:\n            handle.seek(-limit, os.SEEK_END)\n        return handle.read(limit).decode(errors=\"replace\")\n\n\ndef _real_results_root(results_dir: Path) -> Path:\n    root = results_dir.expanduser().absolute()\n    try:\n        metadata = root.lstat()\n    except OSError as exc:\n        raise SandboxError(f\"results directory is unavailable: {root}: {exc}\") from exc\n    if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):\n        raise SandboxError(f\"results directory must be a real non-symlink directory: {root}\")\n    if root.resolve(strict=True) != root:\n        raise SandboxError(f\"results directory must not traverse symlinks: {root}\")\n    return root\n\n\ndef _results_artifact_path(root: Path, relative_value: str, *, transcript: bool) -> Path:\n    relative = PurePosixPath(relative_value)\n    expected_parts = 2 if transcript else 1\n    if (\n        relative.is_absolute()\n        or len(relative.parts) != expected_parts\n        or any(part in {\"\", \".\", \"..\"} for part in relative.parts)\n        or (transcript and relative.parts[0] != \"transcripts\")\n    ):\n        raise SandboxError(f\"unsafe results artifact path: {relative_value!r}\")\n    current = root\n    for part in relative.parts[:-1]:\n        current /= part\n        try:\n            metadata = current.lstat()","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/evolve.py#L279-L315","documentation":"Even when the leaf is a real directory, _real_results_root requires root.resolve(strict=True) == root — i.e. no parent component of the path may be a symlink. If resolving the path lands on a different inode, some ancestor traverses a symlink, which the trust boundary forbids because the symlink target could be swapped under the harness.","triggerScenarios":"A parent directory of results_dir is a symlink: e.g. /opt/bench -> /mnt/x, and results_dir=/opt/bench/results resolves to /mnt/x/results, which differs from the as-given path.","commonSituations":"Standard symlinked install prefixes (/opt, /var/lib); a workspace root that is a symlink to a volume; PATH-like convenience links used in the results dir argument.","solutions":["Resolve the path yourself first and pass the realpath: `Path(...).resolve(strict=True)`.","Remove or replace the symlinked ancestor with a real directory, or move the results tree under a non-symlinked root.","Document the no-symlink-traversal rule for operators picking the results location."],"exampleFix":"# before\nresults_dir = Path(\"/opt/bench/results\")  # /opt/bench is a symlink\n\n# after: caller resolves to the real inode first\nresults_dir = Path(\"/opt/bench/results\").resolve(strict=True)\n# or point directly at the real volume\nresults_dir = Path(\"/mnt/x/results\")","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef results_dir_no_symlink_traversal(path: Path) -> bool:\n    root = path.expanduser().absolute()\n    try:\n        return root.resolve(strict=True) == root\n    except OSError:\n        return False\n\n# use the realpath to avoid the guard\nresults_dir = Path(...).resolve(strict=True)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Resolve the results path yourself first: Path(...).resolve(strict=True).","Keep the results tree under a non-symlinked volume root.","Audit install prefixes (/opt, /var/lib) for symlinks before pointing the harness at them."],"tags":["workflow-bench","sandbox","security","filesystem","symlink","results-dir"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}