abhigyanpatwari/GitNexus · error · SandboxError

evidence names must be simple relative files: {name!r}

Error message

evidence names must be simple relative files: {name!r}

What it means

Raised by stage_evidence_bundle when an entry name is not a single simple relative filename. PurePosixPath(name) must have exactly one part whose name is not '', '.', or '..'. This blocks path traversal (../), absolute paths (/etc/...), nested subpaths (sub/file), and empty names so an entry cannot escape the destination directory or create unexpected structure.

Source

Thrown at eval/workflow_bench/proposer_sandbox.py:230

def stage_evidence_bundle(
    destination: Path,
    entries: Mapping[str, Any],
    *,
    secrets: Sequence[str] = (),
) -> Path:
    """Write a redacted owner-only evidence bundle with hard byte caps."""

    destination = destination.resolve()
    if destination.exists():
        raise SandboxError(f"evidence destination already exists: {destination}")
    destination.mkdir(parents=True, mode=0o700)
    destination.chmod(0o700)
    total = 0
    try:
        for name, value in entries.items():
            relative = PurePosixPath(name)
            if len(relative.parts) != 1 or relative.name in {"", ".", ".."}:
                raise SandboxError(f"evidence names must be simple relative files: {name!r}")
            payload = _evidence_bytes(value, secrets)
            if len(payload) > MAX_EVIDENCE_FILE_BYTES:
                raise SandboxError(f"evidence exceeds the per-file limit: {name}")
            total += len(payload)
            if total > MAX_BUNDLE_BYTES:
                raise SandboxError("evidence bundle exceeds the total byte limit")
            path = destination / relative.name
            path.write_bytes(payload)
            path.chmod(0o600)
    except BaseException:
        shutil.rmtree(destination, ignore_errors=True)
        raise
    return destination


def _validated_base_url(base_url: str) -> str:
    value = base_url.strip()
    parsed = urlsplit(value)

View on GitHub (pinned to d540b00184)

Solutions

  1. Use only the file's basename as the key: {path.name: path} or PurePosixPath(name).name.
  2. Sanitize any externally sourced name: strip slashes, reject '..' and empty, keep one part.
  3. Build keys from a controlled allowlist of filenames.
  4. Assert len(PurePosixPath(name).parts) == 1 before building the mapping.

Example fix

// before
entries = {str(p): p for p in paths}  # may include 'dir/x'
// after
entries = {p.name: p for p in paths}
assert all(len(PurePosixPath(k).parts) == 1 and k not in {'','.','..'} for k in entries)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import PurePosixPath

def is_simple_name(name: str) -> bool:
    p = PurePosixPath(name)
    return len(p.parts) == 1 and p.name not in {'', '.', '..'}

entries = {k: v for k, v in entries.items() if is_simple_name(k)}
# or fail loud:
assert all(is_simple_name(k) for k in entries), list(entries)

Type guard

from pathlib import PurePosixPath

def is_simple_relative_filename(name: object) -> bool:
    if not isinstance(name, str):
        return False
    p = PurePosixPath(name)
    return len(p.parts) == 1 and p.name not in {'', '.', '..'}

Try / catch

try:
    stage_evidence_bundle(dest, entries, secrets=secrets)
except SandboxError as exc:
    if 'must be simple relative files' in str(exc):
        entries = {PurePosixPath(k).name: v for k, v in entries.items()}
        stage_evidence_bundle(dest, entries, secrets=secrets)
    raise

Prevention

When it happens

Trigger: Passing an entries mapping whose key contains a slash, is absolute, contains a '..' segment, or is empty/dot/dotdot. e.g. {"../escape": ...}, {"/etc/passwd": ...}, {"a/b": ...}, {"": ...}.

Common situations: Caller reused a full path as the key instead of basename; generated name from untrusted/external data without sanitization; key built by string concatenation that produced a leading slash; normalized name that PurePosixPath splits into multiple parts.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/0e847b7c20be67d7. Report an issue: GitHub.