Back to skill

Security audit

archive-extractor

Security checks for vulnerabilities and agentic risk

Overview

This archive extractor is mostly purpose-aligned, but it can automatically install unpinned Python packages and has unsafe archive extraction and deletion behaviors that deserve review before use.

Review this skill before installing in any sensitive environment. Use it only on archives and directories you trust, avoid running it with elevated privileges, avoid --force near valuable existing folders, and prefer preinstalling reviewed dependencies in an isolated environment instead of allowing automatic pip installs.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/extract.py:130
Finding

Unsafe TAR Extraction on Supported Legacy Python Versions

Content
View full analysis

Vulnerability Details

File Location: scripts/extract.py, lines 130-138
Vulnerability Type: Path traversal and unsafe link extraction
Risk Level: High

Vulnerable Code

python
def _safe_tar_extract(tf: tarfile.TarFile, dest: Path) -> None:
    """Use 'data' filter on Python 3.12+ for security; fall back gracefully."""
    if hasattr(tarfile, "data_filter"):
        try:
            tf.extractall(dest, filter="data")
            return
        except TypeError:
            pass
    tf.extractall(dest)

Technical Analysis

The project advertises compatibility with Python 3.8 and later, but safe TAR filtering is only used when tarfile.data_filter is available. On older supported runtimes, or if the filtered call raises TypeError, execution falls back to unrestricted TarFile.extractall().

An attacker-controlled TAR can contain absolute paths, names containing parent-directory components, or unsafe symbolic and hard links. Without explicit member and link-target validation, extraction may place or overwrite files outside the intended output directory. The exploit does not require command injection; it abuses archive metadata interpreted by the TAR extraction implementation.

Attack Path

  1. An attacker prepares a TAR archive containing traversal paths or unsafe links that resolve outside the extraction directory.
  2. The archive is supplied to a user or agent that invokes this skill on a Python runtime where the data filter is unavailable or not accepted.
  3. _safe_tar_extract() reaches the unfiltered tf.extractall(dest) fallback.
  4. Malicious members are written outside dest, subject to the filesystem permissions of the running process.
  5. The attacker may overwrite application configuration, user files, scripts, or other writable targets.

Impact Assessment

Successful exploitation permits arbitrary file creation or overwrite anywhere writable by the skill proces ...[truncated 277 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not fall back to unrestricted extractall() on supported legacy runtimes.
  • Resolve and validate every member destination before extraction, ensuring it remains beneath the resolved output directory.
  • Reject absolute paths, drive-qualified paths, parent-directory traversal, device entries, FIFOs, and unsafe symbolic or hard links.
  • Validate link targets independently rather than validating only the archive member name.
  • Prefer requiring a Python runtime with secure TAR filtering and fail closed if the filter cannot be applied.
  • Extract into a newly created isolated directory and remove it on any validation or extraction failure.
  • Add regression tests using absolute-path, traversal, symlink, and hard-link archive fixtures.

T08 · Insecure Dependencies

Warning
Location
scripts/extract.py:41
Finding

Automatic Installation of Unpinned Runtime Dependencies

Content
View full analysis

Vulnerability Details

File Location: scripts/extract.py, lines 41-72
Vulnerability Type: Unpinned runtime dependency installation and supply-chain exposure
Risk Level: Medium

Vulnerable Code

python
def _pip_install(package: str) -> bool:
    """Install *package* into the current interpreter's site-packages."""
    logger.info("Installing %s ...", package)
    try:
        subprocess.check_call(
            [sys.executable, "-m", "pip", "install", "--quiet", package],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.PIPE,
        )
        importlib.invalidate_caches()
        return True
    except subprocess.CalledProcessError as exc:
        logger.warning("pip install %s failed: %s", package,
                       getattr(exc, "stderr", b"").decode(errors="replace").strip())
        return False


def _import_optional(import_name: str, pip_name: str):
    """Try to import *import_name*; auto-install via pip if missing. Returns module or None."""
    try:
        return importlib.import_module(import_name)
    except ImportError:
        pass
    if _pip_install(pip_name):
        importlib.invalidate_caches()
        try:
            return importlib.import_module(import_name)
        except ImportError:
            pass
    logger.warning("Could not load '%s' even after installing '%s'.", import_name, pip_name)
    return None

The unpinned package names are selected here:

python
def _get_rarfile():
    global _rarfile_mod
    if _rarfile_mod is None:
        _rarfile_mod = _import_optional("rarfile", "rarfile")
        if _rarfile_mod is not None:
            _rarfile_mod.UNRAR_TOOL = None
            _rarfile_mod.ALT_TOOL   = None
    return _rarfile_mod

def _get_py7zr():
    global _py7zr_mod
    if _py7zr_mod is None:
        _py7zr_mod = _import_optional("py7zr", "py7zr")
    return _py7zr_mod

...[truncated 1864 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove automatic dependency installation from archive-processing execution paths.
  • Declare reviewed dependencies in a lock file with exact versions and cryptographic hashes.
  • Install dependencies during an explicit setup phase in an isolated virtual environment.
  • Require a trusted package index and prevent pip configuration from silently redirecting dependency resolution.
  • Pin and review transitive dependencies as well as direct dependencies.
  • If a backend is unavailable, fail safely with installation instructions rather than modifying the environment automatically.
  • Run dependency vulnerability and provenance checks as part of release preparation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/extract.py:140
Finding

Unbounded Archive Expansion Enables Resource Exhaustion

Content
View full analysis

Vulnerability Details

File Location: scripts/extract.py, lines 140-183 and 218-268
Vulnerability Type: Archive bomb and uncontrolled resource consumption
Risk Level: Medium

Vulnerable Code

python
def _extract_single_compressed(src: Path, dest_dir: Path, stem: str,
                                open_fn) -> None:
    """Generic single-file decompressor (.gz / .bz2 / .xz)."""
    out = dest_dir / stem
    with open_fn(src, "rb") as fin, open(out, "wb") as fout:
        shutil.copyfileobj(fin, fout)


def _extract_zip(src: Path, dest_dir: Path) -> None:
    if not zipfile.is_zipfile(src):
        raise ValueError(f"Not a valid ZIP file: {src.name}")
    with zipfile.ZipFile(src, "r") as zf:
        zf.extractall(dest_dir)


def _extract_tar(src: Path, dest_dir: Path) -> None:
    if not tarfile.is_tarfile(src):
        raise ValueError(f"Not a valid TAR file: {src.name}")
    with tarfile.open(src, "r:*") as tf:
        _safe_tar_extract(tf, dest_dir)


def _extract_rar(src: Path, dest_dir: Path) -> None:
    rf = _get_rarfile()
    if rf is None:
        raise RuntimeError(
            "rarfile not available — cannot extract .rar files. "
            "Run: pip install rarfile"
        )
    with rf.RarFile(str(src)) as archive:
        archive.extractall(str(dest_dir))


def _extract_7z(src: Path, dest_dir: Path) -> None:
    p7 = _get_py7zr()
    if p7 is None:
        raise RuntimeError(
            "py7zr not available — cannot extract .7z files. "
            "Run: pip install py7zr"
        )
    with p7.SevenZipFile(str(src), mode="r") as archive:
        archive.extractall(str(dest_dir))

Recursive processing is also performed without a cumulative extraction budget:

python
def process_dir(directory: Path, force: bool, depth: int = 0) -> None:
    """DFS: extract every archive, then recurse into extracted output."""
    if depth > MAX_
...[truncated 2118 chars]
Remediation
View remediation

Remediation Suggestions

  • Enforce configurable limits for total expanded bytes, individual file size, member count, nesting depth, and aggregate archive count.
  • Reject suspicious compression ratios and implausible declared sizes before extraction where metadata is available.
  • Replace unrestricted streaming copies with bounded copies that abort after a defined output limit.
  • Track a cumulative extraction budget across recursive calls rather than applying limits independently to each archive.
  • Check available disk space and inode capacity before and during extraction.
  • Apply execution timeouts and resource limits in a sandboxed worker process.
  • Stop processing immediately when a limit is reached and securely remove partial output.
  • Add tests covering high-ratio compression, excessive member counts, and nested archive bombs.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/extract.py:192
Finding

Force Mode Can Delete an Unrelated Colliding Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/extract.py, lines 192-210
Vulnerability Type: Unsafe recursive deletion caused by output-name collision
Risk Level: Medium

Vulnerable Code

python
handler, stem = _match_ext(archive.name.lower())
if handler is None:
    return None

out_dir = dest_parent / stem
marker  = out_dir / MARKER_FILE

# ── Idempotency ──
if out_dir.exists():
    if not force and marker.exists():
        logger.info("[SKIP]   %s (already extracted)", archive.name)
        return out_dir
    if force:
        logger.info("[FORCE]  Cleaning %s", out_dir)
        shutil.rmtree(out_dir, ignore_errors=True)
    else:
        logger.info("[RESUME] Incomplete extraction: %s", archive.name)

Technical Analysis

The output directory is derived solely from the lowercased archive filename stem. When force mode is enabled, any existing path at that derived location is recursively deleted. The code does not require a valid ownership marker, verify that the directory was created by this tool, request confirmation, or ensure that the target is inside a dedicated managed extraction root.

For example, forcing extraction of report.zip beside an unrelated directory named report causes that directory to be passed to shutil.rmtree(). The ignore_errors=True argument also suppresses deletion errors and reduces visibility into partial deletion.

Attack Path

  1. A writable destination contains an existing directory with valuable files, such as report.
  2. An attacker supplies or renames an archive so its stem collides with that directory, such as report.zip.
  3. A user or automated workflow invokes the extractor with --force.
  4. out_dir resolves to the existing report directory.
  5. shutil.rmtree() recursively deletes its contents before archive extraction begins.

Impact Assessment

Exploitation can delete unrelated files and directories writable ...[truncated 305 chars]

Remediation
View remediation

Remediation Suggestions

  • Never recursively delete a pre-existing directory solely because its name matches an archive stem.
  • Create a cryptographically random or otherwise collision-resistant extraction directory under a dedicated managed root.
  • Before deletion, require and verify an ownership marker containing tool-specific metadata for the exact archive and output directory.
  • Refuse force extraction when the destination exists but cannot be proven to have been created by this tool.
  • Require explicit confirmation for destructive operations in interactive use.
  • Resolve the deletion target and verify that it is a strict descendant of the dedicated extraction root.
  • Avoid ignore_errors=True; report failures and abort if cleanup is incomplete.
  • Preserve or back up existing output unless the caller explicitly authorizes its removal.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented purpose frames the skill as a simple local archive extractor, but it also performs runtime package installation via pip, which introduces subprocess execution and network-dependent code retrieval. That mismatch is dangerous because users or orchestrators may approve the skill for local file handling without realizing it can fetch and install unpinned third-party code at runtime.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill advertises itself as a dependency-free archive extractor, but it can perform package installation over the network on first use. That mismatch is dangerous because users may grant it trust appropriate for local file handling while it actually modifies the Python environment and fetches code from external sources.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Spawning pip as a subprocess is not necessary for basic archive extraction and gives the skill the ability to change the local environment and execute package installation workflows. In this context, that broadens the attack surface to supply-chain compromise, unintended dependency execution, and policy bypass in environments that expect skills to be non-installing utilities.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill declares no explicit tool scope even though its documented operation clearly implies file reads, file writes, and shell/process execution. In an agent environment, missing scope boundaries can let the skill be invoked with broader-than-expected privileges, increasing the chance of unsafe file access or command execution beyond archive extraction.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The high-level description promises only Python 3.8+ and no local software, but later documentation states that additional libraries will be installed on first use. This discrepancy can defeat user consent and security review processes by understating the skill's actual behavior and trust requirements.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The claim that the skill needs only Python 3.8+ and no local software is misleading because first use triggers pip installation of extra packages. Misleading dependency claims can cause the skill to run in restricted or high-trust environments where outbound network access and dynamic dependency changes were not expected or approved.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Omitting a prominent warning that first use will auto-install packages via pip deprives users of meaningful consent for network access, subprocess execution, and trust in third-party packages. In agent workflows, this can lead to silent policy violations or accidental execution in environments where dynamic installs are prohibited.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The claim of 'no other network calls' is misleading because pip installation inherently retrieves packages and metadata from package sources unless fully offline. Misrepresenting network behavior can cause operators to run the skill in restricted or high-trust contexts under false assumptions about its capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Automatic pip installation changes the environment and may access the network without explicit, informed user consent beyond normal logging. In a skill advertised for simple archive extraction, implicit installation is especially risky because users may not expect side effects outside the target files being processed.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

The code launches pip at runtime to install packages, which introduces network access and arbitrary third-party code into the execution path of a skill whose stated purpose is only archive extraction. Even though the package names are hardcoded elsewhere, invoking pip from the skill expands capability far beyond extraction and creates supply-chain and environment-modification risk.

Content

Scanner excerpt · scripts/extract.py (reported line 47)May include surrounding context.

python
"""Install *package* into the current interpreter's site-packages."""
    logger.info("Installing %s ...", package)
    try:
        subprocess.check_call(
            [sys.executable, "-m", "pip", "install", "--quiet", package],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.PIPE,

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The phrase 'Zero local-software dependency' suggests no additional software changes are made locally, yet the next lines say .rar and .7z support depends on packages being auto-installed via pip. That is a direct contradiction in the skill's own documentation about how the feature works.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.