zed-industries/zed · error · ValueError

archive member escapes destination: {member.name}

Error message

archive member escapes destination: {member.name}

What it means

The sibling guard to the link check: for every member, safe_extract_archive() resolves destination/member.name and requires the result to stay at or under the (resolved) destination. A member like '../evil' or an absolute path resolves outside and is rejected — this is the zip-slip/tar-slip path-traversal defense.

Source

Thrown at crates/eval_cli/zed_eval/common.py:51


def load_json(path: pathlib.Path) -> dict[str, Any] | None:
    try:
        data = json.loads(path.read_text())
    except (OSError, json.JSONDecodeError):
        return None
    return data if isinstance(data, dict) else None


def safe_extract_archive(archive: tarfile.TarFile, destination: pathlib.Path) -> None:
    destination = destination.resolve()
    members = archive.getmembers()
    for member in members:
        if member.issym() or member.islnk():
            raise ValueError(f"archive links are not supported: {member.name}")
        target = (destination / member.name).resolve()
        if destination != target and destination not in target.parents:
            raise ValueError(f"archive member escapes destination: {member.name}")
    archive.extractall(destination, members=members)


def command_exists(name: str) -> bool:
    return shutil.which(name) is not None


def run_command(
    command: list[str], *, capture: bool = False
) -> subprocess.CompletedProcess[str]:
    return subprocess.run(command, check=True, text=True, capture_output=capture)


def dedupe_preserving_order(values: list[str]) -> list[str]:
    seen = set()
    result = []
    for value in values:
        if value in seen:

View on GitHub (pinned to bc538def45)

Solutions

  1. Do not extract the archive — members that attempt escape are treated as malicious by design
  2. Inspect with `tar tvf bundle.tar.gz` to locate the offending paths
  3. Repack legitimately-needed content with relative paths only: `tar czf fixed.tar.gz -C clean-dir .`
  4. Report the archive to its producer if the traversal looks accidental

Example fix

# before
# archive member '../../etc/cron.d/x' → ValueError: archive member escapes destination

# after
# obtain a clean copy of the content and repack with relative paths:
cd trusted-source && tar czf ../fixed.tar.gz .
Defensive patterns

Strategy: validation

Validate before calling

import pathlib, tarfile

def escaping_members(archive, destination):
    dest = pathlib.Path(destination).resolve()
    bad = []
    for m in archive.getmembers():
        target = (dest / m.name).resolve()
        if target != dest and dest not in target.parents:
            bad.append(m.name)
    return bad

Type guard

import pathlib

def is_safe_member(member, destination):
    target = (pathlib.Path(destination) / member.name).resolve()
    return target == pathlib.Path(destination).resolve() or pathlib.Path(destination).resolve() in target.parents

Try / catch

try:
    safe_extract_archive(archive, destination)
except ValueError as e:
    if "escapes destination" in str(e):
        raise SystemExit(f"refusing malicious archive: {e}")
    raise

Prevention

When it happens

Trigger: Extracting a crafted or corrupted archive whose member names contain '../' sequences or absolute paths; archives from tools emitting up-level references; malicious test fixtures for extraction code.

Common situations: Downloading task bundles from untrusted sources; archives packed on Windows with absolute paths; repackaging bugs producing malformed member names.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/11fb763fb671d021. Report an issue: GitHub.