crewAIInc/crewAI · critical · ValueError
Blocked unsupported tar member: {member.name!r}
Error message
Blocked unsupported tar member: {member.name!r} What it means
`_safe_extract_tar` only permits regular files, directories, symlinks, and hardlinks. Any other tar member type — device nodes (character/block), FIFOs — is rejected with `ValueError` before extraction, because such members have no legitimate purpose in a skill archive and are a classic tar-bomb primitive.
Source
Thrown at lib/cli/src/crewai_cli/skills/main.py:440
def _safe_extractall(tf: tarfile.TarFile, dest: Path) -> None:
"""Path-traversal-safe extraction for Python versions without tar filters.
Validates both the member's own path and, for symlink/hardlink members,
the link target. Without the link-target check a malicious archive can
plant a symlink that escapes ``dest`` (e.g. ``link -> /home/user/.ssh``)
followed by a regular member written *through* that link
(``link/authorized_keys``), escaping ``dest`` even though every member
name resolves inside it. This mirrors the protection that
``tarfile.extractall(..., filter="data")`` provides when available.
"""
dest_resolved = dest.resolve()
for member in tf.getmembers():
member_path = (dest / member.name).resolve()
if not member_path.is_relative_to(dest_resolved):
raise ValueError(f"Blocked path traversal attempt: {member.name!r}")
if not (member.isfile() or member.isdir() or member.issym() or member.islnk()):
raise ValueError(f"Blocked unsupported tar member: {member.name!r}")
if member.issym() or member.islnk():
link_target = member.linkname
# Absolute link targets always escape the destination.
if os.path.isabs(link_target):
raise ValueError(
f"Blocked link target escaping destination: "
f"{member.name!r} -> {link_target!r}"
)
# 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: S202View on GitHub (pinned to 754d7323be)
Solutions
- Do not install this archive; report it to the registry maintainers if it came from the registry.
- If you authored the skill, rebuild the tarball from a clean directory containing only regular files/dirs (e.g. re-run `crewai skill publish` from a sanitized folder).
- Inspect with `tar -tvzf archive.tar.gz` to find the offending member.
Defensive patterns
Strategy: try-catch
Validate before calling
import tarfile
def only_supported_members(path: str) -> bool:
with tarfile.open(path) as tf:
return all(m.isfile() or m.isdir() or m.issym() or m.islnk() for m in tf.getmembers()) Try / catch
try:
_safe_extract_tar(tf, dest)
except ValueError as exc:
if "unsupported tar member" in str(exc):
log_security_event(f"non-file member in skill archive: {exc}")
delete_archive()
raise Prevention
- Build skill archives from clean directories containing only regular files and folders.
- Run `tar -tvzf` on your own archives before publishing to catch device/FIFO members.
- Treat unsupported-member hits on third-party skills as supply-chain red flags.
When it happens
Trigger: Installing a skill archive containing a device member (e.g. `/dev/null` style char device created by a poorly configured `tar -czf /dev/...`) or a FIFO. The `not (member.isfile() or member.isdir() or member.issym() or member.islnk())` branch fires.
Common situations: A skill author accidentally tarred device files or special nodes from their filesystem; deliberately malicious archives trying to plant devices; rare GNU tar options that store sparseness/special types the check does not whitelist.
Related errors
- Blocked path traversal attempt: {member.name!r}
- Blocked link target escaping destination: {member.name!r} ->
- Blocked path traversal attempt: {member!r}
- Invalid skill reference: org and name must be single, non-em
- Invalid skill reference. Use the format @org/name.
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/827c1cd8f6bf4195.
Report an issue: GitHub.