{"record":{"id":"11fb763fb671d021","repo":"zed-industries/zed","slug":"archive-member-escapes-destination-member-name","errorCode":null,"errorMessage":"archive member escapes destination: {member.name}","messagePattern":"archive member escapes destination: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"crates/eval_cli/zed_eval/common.py","lineNumber":51,"sourceCode":"\n\ndef load_json(path: pathlib.Path) -> dict[str, Any] | None:\n    try:\n        data = json.loads(path.read_text())\n    except (OSError, json.JSONDecodeError):\n        return None\n    return data if isinstance(data, dict) else None\n\n\ndef safe_extract_archive(archive: tarfile.TarFile, destination: pathlib.Path) -> None:\n    destination = destination.resolve()\n    members = archive.getmembers()\n    for member in members:\n        if member.issym() or member.islnk():\n            raise ValueError(f\"archive links are not supported: {member.name}\")\n        target = (destination / member.name).resolve()\n        if destination != target and destination not in target.parents:\n            raise ValueError(f\"archive member escapes destination: {member.name}\")\n    archive.extractall(destination, members=members)\n\n\ndef command_exists(name: str) -> bool:\n    return shutil.which(name) is not None\n\n\ndef run_command(\n    command: list[str], *, capture: bool = False\n) -> subprocess.CompletedProcess[str]:\n    return subprocess.run(command, check=True, text=True, capture_output=capture)\n\n\ndef dedupe_preserving_order(values: list[str]) -> list[str]:\n    seen = set()\n    result = []\n    for value in values:\n        if value in seen:","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/eval_cli/zed_eval/common.py#L33-L69","documentation":"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.","triggerScenarios":"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.","commonSituations":"Downloading task bundles from untrusted sources; archives packed on Windows with absolute paths; repackaging bugs producing malformed member names.","solutions":["Do not extract the archive — members that attempt escape are treated as malicious by design","Inspect with `tar tvf bundle.tar.gz` to locate the offending paths","Repack legitimately-needed content with relative paths only: `tar czf fixed.tar.gz -C clean-dir .`","Report the archive to its producer if the traversal looks accidental"],"exampleFix":"# before\n# archive member '../../etc/cron.d/x' → ValueError: archive member escapes destination\n\n# after\n# obtain a clean copy of the content and repack with relative paths:\ncd trusted-source && tar czf ../fixed.tar.gz .","handlingStrategy":"validation","validationCode":"import pathlib, tarfile\n\ndef escaping_members(archive, destination):\n    dest = pathlib.Path(destination).resolve()\n    bad = []\n    for m in archive.getmembers():\n        target = (dest / m.name).resolve()\n        if target != dest and dest not in target.parents:\n            bad.append(m.name)\n    return bad","typeGuard":"import pathlib\n\ndef is_safe_member(member, destination):\n    target = (pathlib.Path(destination) / member.name).resolve()\n    return target == pathlib.Path(destination).resolve() or pathlib.Path(destination).resolve() in target.parents","tryCatchPattern":"try:\n    safe_extract_archive(archive, destination)\nexcept ValueError as e:\n    if \"escapes destination\" in str(e):\n        raise SystemExit(f\"refusing malicious archive: {e}\")\n    raise","preventionTips":["Extract only through safe_extract_archive (or extractall(filter='data') on Python 3.12+)","List members with tar -t and scan for '..' and absolute paths before extraction","Quarantine archives that come from untrusted origins"],"tags":["python","security","tarfile","path-traversal"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}