crewAIInc/crewAI · critical · ValueError

Blocked path traversal attempt: {member!r}

Error message

Blocked path traversal attempt: {member!r}

What it means

The ZIP counterpart of the tar checks: `_safe_extract_zip` resolves every entry name from `zf.namelist()` against the destination and raises `ValueError` if any resolves outside it, blocking Zip Slip attacks before `extractall`. It guards the ZIP branch of skill installation/unpacking.

Source

Thrown at lib/cli/src/crewai_cli/skills/main.py:467

            # Hardlink names are relative to the archive root; symlink
            # targets are relative to the member's own directory.
            anchor = dest if member.islnk() else (dest / member.name).parent
            resolved_target = (anchor / link_target).resolve()
            if not resolved_target.is_relative_to(dest_resolved):
                raise ValueError(
                    f"Blocked link target escaping destination: "
                    f"{member.name!r} -> {link_target!r}"
                )
    tf.extractall(dest)  # noqa: S202


def _safe_extract_zip(zf: zipfile.ZipFile, dest: Path) -> None:
    """Path-traversal-safe ZIP extraction."""
    dest_resolved = dest.resolve()
    for member in zf.namelist():
        member_path = (dest / member).resolve()
        if not member_path.is_relative_to(dest_resolved):
            raise ValueError(f"Blocked path traversal attempt: {member!r}")
    zf.extractall(dest)  # noqa: S202

View on GitHub (pinned to 754d7323be)

Solutions

  1. Do not install the skill; report the archive to the registry maintainers.
  2. Inspect the payload first: `python -c "import zipfile; print('\n'.join(zipfile.ZipFile('s.zip').namelist()))"` to see offending entries.
  3. If you authored the skill, rebuild the ZIP from a clean directory with relative paths only and republish.
Defensive patterns

Strategy: try-catch

Validate before calling

import zipfile
from pathlib import Path

def zip_entries_safe(path: str, dest: Path) -> bool:
    dest_r = dest.resolve()
    with zipfile.ZipFile(path) as zf:
        return all((dest / n).resolve().is_relative_to(dest_r) for n in zf.namelist())

Try / catch

from crewai_cli.skills.main import _safe_extract_zip

try:
    with zipfile.ZipFile(archive) as zf:
        _safe_extract_zip(zf, dest)
except ValueError as exc:
    if "path traversal" in str(exc):
        report_and_delete(archive)  # do not extract manually
    raise

Prevention

When it happens

Trigger: Installing a skill delivered as a ZIP containing entries like `../../.bashrc`, `../evil.txt`, or absolute paths such as `/tmp/x`; any `member_path.is_relative_to(dest_resolved)` violation over `zf.namelist()`.

Common situations: Malicious or tampered ZIP payloads from a registry download_url; ZIPs produced by tools that store absolute entry names; archives that combine `..` segments with backslashes on Windows-normalized names.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/cee0f8651721a764. Report an issue: GitHub.