Back to skill

Security audit

Create Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly aligned with creating and importing skills, but its ZIP import helper can write outside the intended folder and its registration step persistently changes the user's EasyClaw skills directory.

Review this skill before installing or using it on ZIP files from others. Only import packages you trust, avoid running the ZIP extraction helper on untrusted archives unless it is fixed to validate paths, and confirm before allowing it to copy anything into ~/.easyclaw/skills.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/easyclaw_unzip_skill.py:121
Finding

ZIP Path Traversal Allows Arbitrary File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/easyclaw_unzip_skill.py, lines 121–140
Vulnerability Type: ZIP path traversal
Risk Level: High

Vulnerable Code:

python
if member.startswith(root_folder + '/'):
    # Calculate relative path
    relative_path = member[len(root_folder) + 1:]
    if not relative_path:  # Skip empty paths
        continue

    target_file = os.path.join(target_path, relative_path)

    # If it's a folder
    if member.endswith('/'):
        os.makedirs(target_file, exist_ok=True)
    else:
        # Ensure parent directory exists
        parent_dir = os.path.dirname(target_file)
        if parent_dir:
            os.makedirs(parent_dir, exist_ok=True)
        # Extract file
        with zip_file.open(member) as source, open(target_file, 'wb') as target:
            target.write(source.read())

Technical Analysis

The single-root-folder extraction branch removes the archive's root prefix and directly combines the remaining member name with target_path. It does not normalize the resulting path or verify that the resolved destination remains inside the intended extraction directory.

An archive member such as skill/../../outside.txt satisfies the member.startswith(root_folder + '/') check. After removing the root prefix, relative_path becomes ../../outside.txt. Passing that value to os.path.join() does not remove the traversal components. The subsequent os.makedirs() and open(..., 'wb') operations therefore act on a location outside target_path.

The filename validation at lines 93–98 applies only to the ZIP archive's base filename, not to individual archive members, so it does not prevent this attack. The risk is amplified because SKILL.md instructs the Agent to use this script when processing user-provided Skill archives.

Attack Path

  1. An attacker creates a ZIP archive with a single apparent root directory.
  2. The archiv ...[truncated 1078 chars]
Remediation
View remediation

Remediation Suggestions

  1. Resolve the extraction root and every candidate destination to canonical absolute paths before creating directories or files.
  2. Use os.path.commonpath() to verify that every resolved destination remains inside the extraction root.
  3. Reject absolute paths, drive-qualified paths, UNC paths, empty member names, and any member containing a .. path component.
  4. Validate every archive member before extracting any content so an invalid archive cannot be partially written.
  5. Extract files incrementally only after all members pass validation.
  6. Add regression tests covering traversal paths, mixed path separators, absolute paths, drive-qualified paths, and valid nested files.

Example containment check:

python
root = os.path.realpath(target_path)
destination = os.path.realpath(os.path.join(root, relative_path))

try:
    contained = os.path.commonpath([root, destination]) == root
except ValueError:
    contained = False

if not contained:
    raise ValueError(f"Unsafe ZIP member path: {member}")

Apply equivalent validation consistently to both extraction branches.

Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill claims to be a guide, but it directs command-line ZIP processing and extraction logic that can create directories and write files. In the context of importing untrusted skill packages, hidden operational behavior increases the chance of unsafe handling of attacker-supplied archives and unintended modification of the local environment.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims to be a guide, but it directs command-line ZIP processing and extraction logic that can create directories and write files. In the context of importing untrusted skill packages, hidden operational behavior increases the chance of unsafe handling of attacker-supplied archives and unintended modification of the local environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs the agent to execute helper scripts that extract ZIPs and register skills, which implies filesystem write capability, but it declares no explicit tool scope or permissions. This is dangerous because a broadly-triggered skill can cause file writes or installation-like behavior without clear authorization boundaries or user-visible consent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation description is broad enough that the skill may trigger for many user requests related to skills, including ambiguous cases. Because this skill includes instructions for extraction and registration, overly broad triggering raises the risk of premature execution of sensitive file-writing or installation actions in contexts where the user only wanted advice.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest describes a guide-oriented skill for creating or importing skills, but this file implements direct local archive extraction, creates directories, writes arbitrary files, and may delete the target directory on failure. Those are operational filesystem effects rather than merely guidance, and they materially expand what the skill actually does.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation says to execute create-skill/scripts/easyclaw_unzip_skill.py for extraction, but the usage example shows python yuanqi_ai_bot_unzip_skill.py "zip_path". These two instructions actively conflict, which can mislead a user or agent about what code should actually be run.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.