Back to skill

Security audit

Skill Creator

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent skill-authoring helper, but its packaging script can accidentally include sensitive local files through symlinks.

Review before installing or using in automated workflows. Use it only on trusted skill directories, avoid packaging directories that may contain symlinks, and run its helper scripts in a sandbox or low-privilege workspace until the symlink and path-containment issues are fixed.

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

Warning
Location
scripts/init_skill.py:195
Finding

Output Directory Escape Through Unvalidated Skill Name

Content
View full analysis

Vulnerability Details

File Location: scripts/init_skill.py, lines 195 and 286-287
Vulnerability Type: Path traversal and arbitrary directory creation
Risk Level: Medium

Vulnerable Code

python
# Line 195
skill_dir = Path(path).resolve() / skill_name
python
# Lines 286-287
skill_name = sys.argv[1]
path = sys.argv[3]

The resulting attacker-controlled path is subsequently used to create a directory and write files:

python
skill_dir.mkdir(parents=True, exist_ok=False)

skill_md_path = skill_dir / 'SKILL.md'
skill_md_path.write_text(skill_content)

scripts_dir = skill_dir / 'scripts'
scripts_dir.mkdir(exist_ok=True)
example_script = scripts_dir / 'example.py'
example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name))
example_script.chmod(0o755)

Technical Analysis

The command-line help states that skill names must contain only lowercase letters, digits, and hyphens, but main() does not enforce this restriction before passing skill_name to init_skill().

Although the supplied base path is resolved, the final combined path is not checked for containment within that base directory. A skill name containing traversal components, such as ../../target, can escape the intended output directory. An absolute skill name can also cause pathlib path composition to discard the base path.

The existence check prevents writing into an already existing target directory, but it does not prevent the creation of a new attacker-selected path elsewhere in the filesystem. The program then creates multiple files and marks the generated example script as executable.

Attack Path

  1. An attacker or untrusted automation controls the skill-name argument passed to init_skill.py.
  2. The attacker supplies a traversal value such as ../../attacker-target, or an absolute path to a nonexistent writable directory.
  3. The script combines this value with the ...[truncated 1104 chars]
Remediation
View remediation

Remediation Suggestions

  1. Enforce the documented skill-name format before constructing any path:

    python
    import re
    
    if not re.fullmatch(r'[a-z0-9]+(?:-[a-z0-9]+)*', skill_name):
        raise ValueError(
            "Skill name must contain lowercase letters, digits, and single hyphens only"
        )
    
  2. Explicitly reject absolute paths, path separators, . components, and .. components.

  3. Resolve both the base directory and final destination, then verify containment:

    python
    base_dir = Path(path).resolve()
    skill_dir = (base_dir / skill_name).resolve()
    
    if skill_dir.parent != base_dir:
        raise ValueError("Skill directory must be an immediate child of the output directory")
    
  4. Apply the same validation rules in both init_skill.py and quick_validate.py through a shared validation function to prevent policy drift.

  5. Run the utility with the minimum filesystem privileges required, particularly in automated build or packaging environments.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/package_skill.py:68
Finding

Local File Disclosure Through Symlinks During Skill Packaging

Content
View full analysis

Vulnerability Details

File Location: scripts/package_skill.py, lines 68-74
Vulnerability Type: Symlink traversal and unintended archive inclusion
Risk Level: High

Vulnerable Code

python
# Create the .skill file (zip format)
try:
    with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
        # Walk through the skill directory
        for file_path in skill_path.rglob('*'):
            if file_path.is_file():
                # Calculate the relative path within the zip
                arcname = file_path.relative_to(skill_path.parent)
                zipf.write(file_path, arcname)
                print(f"  Added: {arcname}")

Technical Analysis

The packager recursively enumerates files under a supplied skill directory and packages every entry for which Path.is_file() returns true. This test follows symbolic links. ZipFile.write() subsequently reads the referenced target rather than safely rejecting the link.

No code checks whether an entry is a symbolic link or whether its resolved target remains within skill_path. The preceding validation only examines SKILL.md frontmatter and does not inspect package entries for symlinks or external targets.

Consequently, a skill directory controlled by an attacker can contain a symlink whose target is any readable host file. When a victim packages that directory, the target file's contents can be copied into the generated .skill archive under the symlink's apparent path.

Attack Path

  1. An attacker prepares a skill directory with a syntactically valid SKILL.md.

  2. The attacker adds a symbolic link inside the skill, for example:

    bash
    mkdir -p malicious-skill/assets
    ln -s /home/victim/.config/service/credentials malicious-skill/assets/document.txt
    
  3. The victim or an automated service invokes:

    bash
    python scripts/package_skill.py malicious-skill ./dist
    

4 ...[truncated 1017 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject symbolic links explicitly before calling is_file() or ZipFile.write():

    python
    for file_path in skill_path.rglob('*'):
        if file_path.is_symlink():
            raise ValueError(f"Symbolic links are not permitted: {file_path}")
        if not file_path.is_file():
            continue
    
  2. Resolve every candidate path and verify that it remains inside the resolved skill root:

    python
    root = skill_path.resolve()
    
    for file_path in skill_path.rglob('*'):
        if file_path.is_symlink():
            raise ValueError(f"Symbolic links are not permitted: {file_path}")
    
        resolved = file_path.resolve(strict=True)
        if not resolved.is_relative_to(root):
            raise ValueError(f"File escapes skill directory: {file_path}")
    
        if resolved.is_file():
            arcname = resolved.relative_to(root.parent)
            zipf.write(resolved, arcname)
    
  3. On Python versions without Path.is_relative_to(), use os.path.commonpath() and compare the result with the resolved root.

  4. Add symlink and containment checks to validate_skill() so unsafe packages fail before archive creation.

  5. Consider packaging from a copied, normalized staging directory created with no symlink following.

  6. Run packaging in a sandbox with access only to the skill directory and output directory, without user credentials or unrelated host secrets.

  7. Add regression tests covering symlinks to files, symlinks to directories, broken symlinks, nested traversal targets, and valid regular files.

Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says this is a guide for creating effective skills, implying instructional or advisory behavior for authoring or updating skills. The actual code does not provide guidance or assist with skill design; instead, it validates a local skill directory and packages it into a .skill file using zip compression. Its primary purpose is build/distribution tooling, which is materially different from the declared purpose. While packaging may be related to skills, it is a separate operational capability that should be explicitly declared.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description says this is a guide to help users create or update skills. The supplied code does not provide guidance content or interactive creation assistance; instead, it performs concrete validation of a local skill directory by reading SKILL.md from disk, parsing YAML frontmatter, and enforcing allowed properties and formatting constraints. That is a materially different primary purpose: validation tooling rather than guidance for skill creation. There is no evidence of dangerous undeclared behavior beyond local file reading for validation, but the behavior is still mismatched with the declared description.

Content

No source excerpt is available for this finding.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · SKILL.md (reported line 209)May include surrounding context.

md
1. Understand the skill with concrete examples
2. Plan reusable skill contents (scripts, references, assets)
3. Initialize the skill (run init_skill.py)
4. Edit the skill (implement resources and write SKILL.md)
5. Package the skill (run package_skill.py)
6. Iterate based on real usage

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · SKILL.md (reported line 300)May include surrounding context.

md
Any example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them.

#### Update SKILL.md

**Writing Guidelines:** Always use imperative/infinitive form.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · scripts/init_skill.py (reported line 266)May include surrounding context.

python
# Print next steps
    print(f"\n✅ Skill '{skill_name}' initialized successfully at {skill_dir}")
    print("\nNext steps:")
    print("1. Edit SKILL.md to complete the TODO items and update the description")
    print("2. Customize or delete the example files in scripts/, references/, and assets/")
    print("3. Run the validator when ready to check the skill structure")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The description says the skill should be used when users want to create a new skill or update an existing skill that extends Claude's capabilities, which is a wide class of requests and does not define boundaries or negative examples. Because frontmatter description is the primary trigger mechanism, this broad phrasing could overlap with many general requests about improving prompts, workflows, or agent behavior and cause unintended invocation.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

These lines emphasize being clear and comprehensive about what the skill is and when it should be used, but they do not advise authors to constrain trigger scope or include non-trigger cases. In a document about skill creation, omitting that safeguard increases the risk of future skills being written with ambiguous activation criteria.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.