langchain-ai/deepagents · critical · FleetImportError

{info.filename}: unsafe zip path

Error message

{info.filename}: unsafe zip path

What it means

FleetImportError raised by `_validated_entries` (libs/talon/deepagents_talon/fleet_import.py:216) when an archive entry path is deemed unsafe — path traversal or absolute paths. `_normalized_zip_name` normalizes the entry, then `_is_unsafe_zip_path` rejects names that would escape the staging directory (e.g. '../', leading '/', drive letters). This is a zip-slip defense applied before any bytes are written.

Source

Thrown at libs/talon/deepagents_talon/fleet_import.py:216

        lines.append("- Review .mcp.json.setup for requested tools and setup details.")
    if result.interrupt_tools:
        lines.append(
            f"- Add HITL for sensitive tools with "
            f"{INTERRUPT_ON_TOOLS_ENV_KEY}={','.join(result.interrupt_tools)}.",
        )
    return "\n".join(lines) + "\n"


def _validated_entries(archive: zipfile.ZipFile) -> dict[str, zipfile.ZipInfo]:
    entries: dict[str, zipfile.ZipInfo] = {}
    total_size = 0
    for info in archive.infolist():
        name = _normalized_zip_name(info.filename)
        if name is None:
            continue
        if _is_unsafe_zip_path(name):
            msg = f"{info.filename}: unsafe zip path"
            raise FleetImportError(msg)
        if _is_symlink(info):
            msg = f"{name}: symlink entries are not supported"
            raise FleetImportError(msg)
        if info.is_dir():
            continue
        _validate_zip_entry_size(name, info)
        if len(entries) >= _MAX_ZIP_ENTRY_COUNT:
            msg = f"{archive.filename}: too many zip entries"
            raise FleetImportError(msg)
        total_size += info.file_size
        if total_size > _MAX_ZIP_UNCOMPRESSED_BYTES:
            msg = f"{archive.filename}: zip uncompressed size exceeds limit"
            raise FleetImportError(msg)
        entries[name] = info
    return entries


def _normalized_zip_name(name: str) -> str | None:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Rebuild the archive with relative, root-relative paths only (zip the directory contents, not absolute paths).
  2. Reject/inspect suspicious archives: `python -m zipfile -l fleet.zip` and remove entries starting with '/' or containing '..'.
  3. Only import fleet zips from trusted sources; the library intentionally refuses to sanitize unsafe paths.

Example fix

// before
zip -r fleet.zip /home/user/.deepagents   # entries like home/user/.deepagents/x or absolute
// after
cd /home/user/.deepagents && zip -r ../fleet.zip .   # all entries relative to root
Defensive patterns

Strategy: validation

Validate before calling

import zipfile, posixpath
def archive_paths_are_safe(path) -> bool:
    with zipfile.ZipFile(path) as z:
        for name in z.namelist():
            norm = posixpath.normpath(name.lstrip("/").replace("\\", "/"))
            if norm.startswith("..") or posixpath.isabs(name):
                return False
    return True

Try / catch

from deepagents_talon.fleet_import import import_fleet_zip, FleetImportError
try:
    result = import_fleet_zip(source, target)
except FleetImportError as exc:
    if "unsafe zip path" in str(exc):
        raise SystemExit(f"{source} contains a path-traversal entry; do not import untrusted archives") from exc
    raise

Prevention

When it happens

Trigger: Calling `import_fleet_zip` on an archive containing entries like '../evil.py', '/etc/passwd', or names that normalize outside the target. The original `info.filename` is included in the message.

Common situations: Archives crafted maliciously (zip-slip attack) or accidentally built with absolute paths (e.g. `zip -r fleet.zip /home/user/.deepagents` on some platforms); third-party fleet exports containing symlinks or traversal entries.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/c38408e276313915. Report an issue: GitHub.