{"record":{"id":"7322fe0f92fa5544","repo":"abhigyanpatwari/GitNexus","slug":"dependency-symlink-escapes-the-sandbox-workspace","errorCode":null,"errorMessage":"dependency symlink escapes the sandbox workspace: {entry.path}","messagePattern":"dependency symlink escapes the sandbox workspace: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"critical","filePath":"eval/workflow_bench/task_assets.py","lineNumber":681,"sourceCode":"    container: Path,\n    entries: tuple[AssetManifestEntry, ...],\n    *,\n    mount_target: PurePosixPath,\n) -> None:\n    snapshot_boundary = (container / \"payload\").resolve(strict=True)\n    manifest_boundary = PurePosixPath(\"payload\")\n    sandbox_boundary = PurePosixPath(SANDBOX_WORKSPACE)\n    sandbox_mount = sandbox_boundary / mount_target\n    for entry in entries:\n        if entry.kind != \"symlink\":\n            continue\n        target = PurePosixPath(entry.link_target)\n        relative_to_payload = entry.path.relative_to(manifest_boundary)\n        sandbox_resolved = PurePosixPath(\n            posixpath.normpath((sandbox_mount / relative_to_payload.parent / target).as_posix())\n        )\n        if sandbox_resolved != sandbox_boundary and sandbox_boundary not in sandbox_resolved.parents:\n            raise SandboxError(f\"dependency symlink escapes the sandbox workspace: {entry.path}\")\n        manifest_resolved = PurePosixPath(posixpath.normpath((entry.path.parent / target).as_posix()))\n        if manifest_resolved != manifest_boundary and manifest_boundary not in manifest_resolved.parents:\n            continue\n        link = container / Path(*entry.path.parts)\n        try:\n            resolved = link.resolve(strict=True)\n            resolved.relative_to(snapshot_boundary)\n        except (OSError, RuntimeError, ValueError) as exc:\n            raise SandboxError(f\"dependency symlink is dangling or escapes its snapshot: {entry.path}\") from exc\n\n\ndef _preflight_exact_root(clone: Path, relative: PurePosixPath) -> None:\n    \"\"\"Reject symlink/special hazards while permitting replaceable type conflicts.\"\"\"\n\n    flags = os.O_RDONLY | os.O_DIRECTORY | getattr(os, \"O_CLOEXEC\", 0) | getattr(os, \"O_NOFOLLOW\", 0)\n    current = os.open(clone, flags)\n    try:\n        for index, part in enumerate(relative.parts):","sourceCodeStart":663,"sourceCodeEnd":699,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L663-L699","documentation":"_validate_dependency_symlinks resolves each symlink-kind dependency entry under the sandbox mount (/workspace/<mount_target>) and rejects it if the resolved path is neither /workspace itself nor located beneath /workspace. Dependency symlinks are permitted, but only if they stay inside the sandbox boundary.","triggerScenarios":"A dependency snapshot captures a symlink whose link_target, when joined onto its parent under the mount, resolves to an absolute path or a ../../ chain that lands outside /workspace; a misconfigured mount_target shifts the resolved root.","commonSituations":"A dependency tarball ships an absolute symlink (e.g. to /etc/passwd); a symlink with many parent traversals; the mount_target was changed without re-validating link targets.","solutions":["Inspect entry.link_target for the offending dependency and confirm it is relative and stays beneath /workspace","Rebuild the dependency snapshot without escaping symlinks","Fix the mount_target so the resolved link stays inside /workspace"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import posixpath\nfrom pathlib import PurePosixPath\n\nSANDBOX_WORKSPACE = \"/workspace\"\n\ndef escaping_links(entries, mount_target: str) -> list[str]:\n    boundary = PurePosixPath(SANDBOX_WORKSPACE)\n    mount = boundary / PurePosixPath(mount_target)\n    manifest_boundary = PurePosixPath(\"payload\")\n    bad = []\n    for e in entries:\n        if e.get(\"kind\") != \"symlink\":\n            continue\n        rel = PurePosixPath(e[\"path\"]).relative_to(manifest_boundary)\n        tgt = PurePosixPath(e[\"link_target\"])\n        resolved = PurePosixPath(posixpath.normpath((mount / rel.parent / tgt).as_posix()))\n        if resolved != boundary and boundary not in resolved.parents:\n            bad.append(e[\"path\"])\n    return bad","typeGuard":null,"tryCatchPattern":"from eval.workflow_bench.proposer_sandbox import SandboxError\n\ntry:\n    snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)\nexcept SandboxError as exc:\n    if \"escapes the sandbox workspace\" in str(exc):\n        raise SystemExit(f\"dependency symlink escapes /workspace; rebuild the dependency: {exc}\") from exc\n    raise","preventionTips":["Reject dependency tarballs containing absolute symlinks before capture","Validate every symlink-kind dependency entry with the escaping_links check above","Keep mount_target stable; re-validate link targets if it changes"],"tags":["sandbox","symlinks","path-traversal","security","dependencies"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}