Back to skill

Security audit

unzip-all

Security checks for vulnerabilities and agentic risk

Overview

This archive-extraction skill is mostly coherent, but it performs broad recursive file writes and automatic archive deletion without enough safety controls.

Install only if you are comfortable with a Chinese-language recursive extractor that automatically deletes source archives after successful extraction. Avoid using it on untrusted archives or important originals unless you have backups, because crafted archives may overwrite files outside the target folder or exhaust disk/memory, and there is no built-in confirmation or dry run.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/unzip_all.py:35
Finding

ZIP Path Traversal Allows Arbitrary File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/unzip_all.py, lines 35–44
Vulnerability Type: Archive path traversal (Zip Slip)
Risk Level: High

Vulnerable Code

python
original = info.filename
try:
    decoded = original.encode('cp437').decode('gbk')
except:
    decoded = original

target_path = os.path.join(extract_to, decoded)
target_dir = os.path.dirname(target_path)
if target_dir and not os.path.exists(target_dir):
    os.makedirs(target_dir, exist_ok=True)

if not decoded.endswith('/'):
    with open(target_path, 'wb') as f:
        f.write(zf.read(info))

Technical Analysis

The archive member name is joined directly to the extraction directory without validating the resulting canonical path. A malicious ZIP entry can contain parent-directory components such as ../, an absolute path, a Windows drive-qualified path, or equivalent separator combinations.

os.path.join() does not guarantee that the resulting path remains under extract_to. The code subsequently creates parent directories and opens the resulting path using wb, which truncates and overwrites an existing file.

Filename recoding does not provide a security boundary. Validation must occur after decoding and path normalization. The code also does not check whether an existing destination component is a symbolic link or other filesystem redirection mechanism.

Attack Path

  1. An attacker creates a ZIP archive containing a member such as ../../target-file.
  2. The attacker supplies the archive to a user or system that invokes this skill.
  3. The skill joins the malicious member name to the selected extraction directory.
  4. The normalized filesystem path escapes the intended extraction directory.
  5. The skill creates any required parent directories and opens the escaped path with write-and-truncate semantics.
  6. The attacker-controlled archive content overwrites the targeted file.
  7. If the targe ...[truncated 768 chars]
Remediation
View remediation

Remediation Suggestions

  • Reject archive member names that are absolute, UNC-based, or Windows drive-qualified.
  • Resolve the extraction root and every candidate destination to canonical absolute paths.
  • Require every resolved candidate to remain strictly beneath the canonical extraction root, preferably using os.path.commonpath() rather than string-prefix comparison.
  • Normalize both slash styles when archives may originate from different operating systems.
  • Reject .. path components before writing.
  • Detect and reject symbolic links and other special archive entries.
  • Prevent traversal through pre-existing symbolic-link components in the destination path.
  • Consider creating files with exclusive, non-overwriting semantics unless overwriting is explicitly requested.
  • Perform all safety checks after filename decoding and immediately before opening the destination.
  • Apply equivalent containment protections to extraction performed through 7-Zip, using a staging directory and validating the resulting tree before moving files into the final destination.

A hardened implementation should follow this pattern:

python
from pathlib import Path, PurePosixPath

root = Path(extract_to).resolve()
member = PurePosixPath(decoded.replace("\\", "/"))

if member.is_absolute() or ".." in member.parts:
    raise ValueError("Unsafe archive member path")

candidate = (root / Path(*member.parts)).resolve()
if candidate == root or root not in candidate.parents:
    raise ValueError("Archive member escapes extraction directory")

T09 · Insecure Skill Coding Practices

Error
Location
scripts/unzip_all.py:34
Finding

Unbounded Recursive Archive Expansion Enables Resource Exhaustion

Content
View full analysis

Vulnerability Details

File Location: scripts/unzip_all.py, lines 34–44 and 121–149
Vulnerability Type: Uncontrolled resource consumption through archive expansion
Risk Level: High

Vulnerable Code

python
with zipfile.ZipFile(file_path, 'r') as zf:
    for info in zf.infolist():
        original = info.filename
        try:
            decoded = original.encode('cp437').decode('gbk')
        except:
            decoded = original
        
        target_path = os.path.join(extract_to, decoded)
        target_dir = os.path.dirname(target_path)
        if target_dir and not os.path.exists(target_dir):
            os.makedirs(target_dir, exist_ok=True)
        
        if not decoded.endswith('/'):
            with open(target_path, 'wb') as f:
                f.write(zf.read(info))
python
while True:
    changed = False
    for root, dirs, files in os.walk(base_dir):
        for f in files:
            full_path = os.path.join(root, f)
            ext = f.lower()
            
            if ext.endswith('.zip'):
                folder = f.replace('.zip', '')
                extract_to = os.path.join(root, folder)
                if extract_zip(full_path, extract_to):
                    os.remove(full_path)
                    changed = True
                break
            elif ext.endswith('.7z'):
                folder = f.replace('.7z', '')
                extract_to = os.path.join(root, folder)
                if extract_7z(full_path, extract_to):
                    os.remove(full_path)
                    changed = True
                break
            elif ext.endswith('.rar'):
                folder = f.replace('.rar', '')
                extract_to = os.path.join(root, folder)
                if extract_rar(full_path, extract_to):
                    os.remove(full_path)
                    changed = True
               
...[truncated 2436 chars]
Remediation
View remediation

Remediation Suggestions

  • Stream ZIP member contents in bounded chunks using zf.open(info) and shutil.copyfileobj() with an explicit buffer instead of calling zf.read(info).
  • Define and enforce a maximum uncompressed size for each member.
  • Maintain a cumulative extraction budget across all nested archives.
  • Enforce limits on archive member count, generated directory count, and total filesystem entries.
  • Reject suspicious compression ratios using compressed and uncompressed size metadata, while recognizing that metadata alone must not be trusted.
  • Set a maximum recursive archive depth and maximum total number of archives processed.
  • Check available disk capacity before and during extraction.
  • Add a processing deadline or cancellation mechanism.
  • Extract into a dedicated staging directory with a storage quota where supported.
  • Do not delete source archives immediately. Delete them only after the entire recursive operation completes successfully, or require explicit user approval.
  • Clean up partial output safely after a rejected or failed extraction.
  • Apply equivalent resource controls to 7z and RAR processing, including subprocess timeouts and operating-system resource restrictions.
  • Record consumed resources in a shared extraction context so nested calls cannot reset the security limits.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented purpose is archive extraction, but the behavior also includes deleting original archives, probing the Windows registry, and invoking an external 7z executable. These undeclared side effects materially increase risk because they can cause irreversible data loss, expand system access beyond simple extraction, and introduce trust in external binaries not clearly disclosed to the user.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill appears to require filesystem access and shell/external executable invocation, but it does not declare any explicit tool scope or permissions. This is dangerous because it obscures the true execution capabilities from reviewers and enforcement systems, increasing the chance of unintended file operations or command execution without adequate policy controls.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The description explicitly states support for Chinese filenames, and later notes automatic GBK encoding handling, which reflects a locale-specific behavior. The file does not indicate that this language/encoding choice is optional or limited to a justified region-specific deployment.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger phrases are broad enough to match ordinary requests such as 'unzip this file' or 'unzip this folder,' which can cause the skill to activate in contexts where the user did not intend recursive extraction, deletion, or external tool usage. In this skill, broad activation is more dangerous because the behavior is recursive and potentially destructive after successful extraction.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/unzip_all.py (reported line 66)May include surrounding context.

python
return False
    try:
        cmd = [SEVEN_ZIP, 'x', file_path, f'-o{extract_to}', '-y']
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            print(f"[OK] 7z: {os.path.basename(file_path)}")
            return True

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

After a successful extraction of a user-supplied archive, the script immediately deletes the original file with os.remove(target) without clearly disclosing this destructive behavior in the skill description. This can cause unexpected data loss and makes rollback or verification impossible if extraction was incomplete, corrupted, or produced unsafe output.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script performs permanent deletion of archive files after extraction with no explicit warning or confirmation. For a utility that may be run on valuable nested archives, this creates a clear unsafe-destructive behavior that can be triggered on normal use rather than only misuse.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

In directory mode, every successfully processed archive discovered during recursive traversal is deleted automatically. Because the advertised purpose is recursive extraction rather than destructive cleanup, this broader behavior can surprise users and result in loss of original archives across an entire folder tree.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

During recursive batch extraction, the tool deletes each located archive as it goes, without a separate confirmation step and without clear disclosure that originals will be removed. In bulk operations this magnifies the blast radius, because many files may be permanently removed before the user notices.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

Comments, usage text, status messages, and errors are presented in Chinese throughout the script, which imposes a specific language on users without opt-in. The file does not indicate that this is a region-specific tool or provide any mechanism to select another language.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.