abhigyanpatwari/GitNexus · critical · SandboxError
dependency symlink escapes the sandbox workspace: {entry.pat
Error message
dependency symlink escapes the sandbox workspace: {entry.path} What it means
_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.
Source
Thrown at eval/workflow_bench/task_assets.py:681
container: Path,
entries: tuple[AssetManifestEntry, ...],
*,
mount_target: PurePosixPath,
) -> None:
snapshot_boundary = (container / "payload").resolve(strict=True)
manifest_boundary = PurePosixPath("payload")
sandbox_boundary = PurePosixPath(SANDBOX_WORKSPACE)
sandbox_mount = sandbox_boundary / mount_target
for entry in entries:
if entry.kind != "symlink":
continue
target = PurePosixPath(entry.link_target)
relative_to_payload = entry.path.relative_to(manifest_boundary)
sandbox_resolved = PurePosixPath(
posixpath.normpath((sandbox_mount / relative_to_payload.parent / target).as_posix())
)
if sandbox_resolved != sandbox_boundary and sandbox_boundary not in sandbox_resolved.parents:
raise SandboxError(f"dependency symlink escapes the sandbox workspace: {entry.path}")
manifest_resolved = PurePosixPath(posixpath.normpath((entry.path.parent / target).as_posix()))
if manifest_resolved != manifest_boundary and manifest_boundary not in manifest_resolved.parents:
continue
link = container / Path(*entry.path.parts)
try:
resolved = link.resolve(strict=True)
resolved.relative_to(snapshot_boundary)
except (OSError, RuntimeError, ValueError) as exc:
raise SandboxError(f"dependency symlink is dangling or escapes its snapshot: {entry.path}") from exc
def _preflight_exact_root(clone: Path, relative: PurePosixPath) -> None:
"""Reject symlink/special hazards while permitting replaceable type conflicts."""
flags = os.O_RDONLY | os.O_DIRECTORY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
current = os.open(clone, flags)
try:
for index, part in enumerate(relative.parts):View on GitHub (pinned to d540b00184)
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
Defensive patterns
Strategy: validation
Validate before calling
import posixpath
from pathlib import PurePosixPath
SANDBOX_WORKSPACE = "/workspace"
def escaping_links(entries, mount_target: str) -> list[str]:
boundary = PurePosixPath(SANDBOX_WORKSPACE)
mount = boundary / PurePosixPath(mount_target)
manifest_boundary = PurePosixPath("payload")
bad = []
for e in entries:
if e.get("kind") != "symlink":
continue
rel = PurePosixPath(e["path"]).relative_to(manifest_boundary)
tgt = PurePosixPath(e["link_target"])
resolved = PurePosixPath(posixpath.normpath((mount / rel.parent / tgt).as_posix()))
if resolved != boundary and boundary not in resolved.parents:
bad.append(e["path"])
return bad Try / catch
from eval.workflow_bench.proposer_sandbox import SandboxError
try:
snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)
except SandboxError as exc:
if "escapes the sandbox workspace" in str(exc):
raise SystemExit(f"dependency symlink escapes /workspace; rebuild the dependency: {exc}") from exc
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- dependency symlink must be a bounded relative link: {relativ
- dependency source must stay inside the repository: {source_p
- dependency target must stay inside the clone: {target_path}
- {label} contains an unsafe path component: {relative}
- unsafe results artifact path: {relative_value!r}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/7322fe0f92fa5544.
Report an issue: GitHub.