{"record":{"id":"53551e802ccdcc20","repo":"abhigyanpatwari/GitNexus","slug":"sandbox-copy-must-not-traverse-a-symlink-child-r","errorCode":null,"errorMessage":"sandbox_copy must not traverse a symlink: {child_relative}","messagePattern":"sandbox_copy must not traverse a symlink: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/task_assets.py","lineNumber":400,"sourceCode":"        self.total_bytes = 0\n        self.budget = budget if budget is not None else _SnapshotBudget()\n        self.allow_symlinks = allow_symlinks\n        self.preserve_modes = preserve_modes\n\n    def copy_descriptor(self, descriptor: int, relative: PurePosixPath) -> None:\n        before = os.fstat(descriptor)\n        if stat.S_ISDIR(before.st_mode):\n            self._record_directory(relative)\n            try:\n                names = sorted(os.listdir(descriptor))\n            except OSError as exc:\n                raise SandboxError(f\"sandbox_copy directory is unreadable: {relative}: {exc}\") from exc\n            for name in names:\n                child_relative = relative / name\n                child_metadata = os.stat(name, dir_fd=descriptor, follow_symlinks=False)\n                if stat.S_ISLNK(child_metadata.st_mode):\n                    if not self.allow_symlinks:\n                        raise SandboxError(f\"sandbox_copy must not traverse a symlink: {child_relative}\")\n                    self._copy_symlink(descriptor, name, child_relative, child_metadata)\n                    continue\n                child = _open_child(descriptor, name, child_relative)\n                try:\n                    self.copy_descriptor(child, child_relative)\n                finally:\n                    os.close(child)\n            after = os.fstat(descriptor)\n            if _mutation_identity(before) != _mutation_identity(after):\n                raise SandboxError(f\"sandbox_copy directory changed while snapshotting: {relative}\")\n            return\n        if not stat.S_ISREG(before.st_mode):\n            raise SandboxError(f\"sandbox_copy accepts only regular files and directories: {relative}\")\n        self._copy_file(descriptor, relative, before)\n\n    def _record_directory(self, relative: PurePosixPath) -> None:\n        self._ensure_parents(relative.parent)\n        self._record(AssetManifestEntry(path=relative, kind=\"directory\"))","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L382-L418","documentation":"In _SnapshotBuilder.copy_descriptor, a child entry is a symlink but the builder was constructed with allow_symlinks=False (the default for sandbox_copy; only sandbox_dependencies set it True). Symlink traversal in copied assets is rejected because a symlink could escape the snapshot boundary.","triggerScenarios":"A sandbox_copy path contains a symlink - e.g. a symlinked file or directory inside the copied tree such as a node_modules/.bin-style link.","commonSituations":"A repo contains convenience symlinks; node_modules/.bin-style symlinks captured via sandbox_copy instead of as a dependency; a symlink loop.","solutions":["Remove or resolve the symlink in the source tree before declaring it in sandbox_copy.","If the symlinked content is a real dependency, declare it under sandbox_dependencies (which permits bounded relative symlinks).","Materialize the symlink target as a real file or directory in the repo."],"exampleFix":"# before - 'tools/current' is a symlink to tools/v1.2\nsandbox_copy:\n  - \"tools/current\"\n\n# after - resolve the link, or declare as a dependency\nsandbox_copy:\n  - \"tools/v1.2\"","handlingStrategy":"validation","validationCode":"import os\n\ndef assert_no_symlinks_in_sandbox_copy(repo, paths):\n    for raw in paths:\n        root = os.path.join(repo, raw)\n        for dirpath, dirnames, filenames in os.walk(root, followlinks=False):\n            for name in dirnames + filenames:\n                p = os.path.join(dirpath, name)\n                if os.path.islink(p):\n                    raise RuntimeError(f\"sandbox_copy contains a symlink: {p}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Resolve or remove symlinks inside any sandbox_copy tree before declaring it.","Declare symlink-bearing dependencies (e.g. node_modules/.bin) under sandbox_dependencies, which allows bounded relative symlinks.","Pre-scan sandbox_copy roots for symlinks to fail fast with a clearer message."],"tags":["security","symlinks","workflow-bench","sandbox"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}