Back to skill

Security audit

creator

Security checks for vulnerabilities and agentic risk

Overview

The skill’s purpose is coherent, but its bundled packaging and initialization scripts have local file-scope weaknesses users should review before installing.

Review before installing if you will use it on untrusted skill folders or automated inputs. Avoid packaging directories you did not inspect, remove symlinks before packaging, and only run the initializer with simple hyphen-case skill names in a controlled output directory.

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:206
Finding

Output Path Traversal in Skill Initializer

Content
View full analysis

Vulnerability Details

File Location: scripts/init_skill.py, lines 206–257
Vulnerability Type: Improper path validation and path traversal
Risk Level: Medium

Vulnerable Code

python
# Determine skill directory path
skill_dir = Path(path).resolve() / skill_name

# Check if directory already exists
if skill_dir.exists():
    print(f"❌ Error: Skill directory already exists: {skill_dir}")
    return None

# Create skill directory
try:
    skill_dir.mkdir(parents=True, exist_ok=False)
    print(f"✅ Created skill directory: {skill_dir}")
except Exception as e:
    print(f"❌ Error creating directory: {e}")
    return None

# Create SKILL.md from template
skill_title = title_case_skill_name(skill_name)
skill_content = SKILL_TEMPLATE.format(
    skill_name=skill_name,
    skill_title=skill_title
)

skill_md_path = skill_dir / 'SKILL.md'
try:
    skill_md_path.write_text(skill_content)
    print("✅ Created SKILL.md")
except Exception as e:
    print(f"❌ Error creating SKILL.md: {e}")
    return None

# Create resource directories with example files
try:
    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)

    references_dir = skill_dir / 'references'
    references_dir.mkdir(exist_ok=True)
    example_reference = references_dir / 'api_reference.md'
    example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title))

    assets_dir = skill_dir / 'assets'
    assets_dir.mkdir(exist_ok=True)
    example_asset = assets_dir / 'example_asset.txt'
    example_asset.write_text(EXAMPLE_ASSET)
except Exception as e:
    print(f"❌ Error creating resource directories: {e}")
    return None

Technical Analysis

The skill_name command-line argument is appended directly to the resolved base directory without enforcing the naming restrictions displayed by the ...[truncated 1717 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate skill_name before using it as a path component:
    • Require a strict expression such as ^[a-z0-9-]{1,64}$.
    • Reject leading or trailing hyphens and consecutive hyphens.
    • Reject absolute paths, path separators, . components, and .. components.
  2. Resolve both the base and final paths, then enforce containment:
python
base_dir = Path(path).resolve()
if not re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", skill_name):
    raise ValueError("Invalid skill name")

skill_dir = (base_dir / skill_name).resolve()
if not skill_dir.is_relative_to(base_dir):
    raise ValueError("Skill path escapes the output directory")
  1. Apply validation inside init_skill() rather than only in command-line handling so imported callers receive the same protection.
  2. Preserve exist_ok=False and fail closed on ambiguous path or permission errors.
  3. Add tests covering absolute names, ../ traversal, nested separators, repeated hyphens, and valid skill names.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/package_skill.py:68
Finding

External File Disclosure Through Symlink-Following During Packaging

Content
View full analysis

Vulnerability Details

File Location: scripts/package_skill.py, lines 68–75
Vulnerability Type: Symlink traversal and unintended file inclusion
Risk Level: Medium

Vulnerable Code

python
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 entries under the selected skill directory but does not reject symbolic links. For a symlink that points to a regular file outside the skill directory, Path.is_file() follows the link and returns true. zipfile.ZipFile.write() then reads the target's contents, while the archive name is derived from the symlink's in-tree path.

Consequently, the generated archive can contain the contents of an arbitrary external file readable by the packaging process, disguised as an ordinary resource within the skill. Validation only checks SKILL.md frontmatter and does not inspect symlinks or package membership boundaries.

Exploitation requires the attacker to prepare or modify the skill directory before a victim packages and distributes it.

Attack Path

  1. An attacker creates a valid skill directory that passes frontmatter validation.
  2. The attacker adds a symlink inside that directory pointing to a sensitive file outside it.
  3. A victim runs the documented package_skill.py command.
  4. rglob() encounters the symlink, and is_file() accepts it by following its target.
  5. zipf.write() reads the external target and stores its contents under the symlink's benign in-archive path.
  6. The victim shares the resulting .skill archive, disclosing the embedded file contents.

Impact Assessment

The issue can ...[truncated 318 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject symbolic links before testing whether an entry is a file:
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
  1. Resolve every candidate and verify that it remains under the resolved skill root:
python
skill_root = skill_path.resolve()

resolved = file_path.resolve(strict=True)
if not resolved.is_relative_to(skill_root):
    raise ValueError(f"File escapes skill directory: {file_path}")
  1. Package only regular files and reject special files such as sockets, devices, and FIFOs.
  2. Extend quick_validate.py to detect symlinks and out-of-tree targets before packaging begins.
  3. Consider an explicit file-type or directory allowlist, maximum individual file size, and maximum total archive size.
  4. Add regression tests using symlinks to readable external files and verify that packaging fails without including their contents.
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 (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This second description-behavior mismatch highlights that the skill does more than provide workflow guidance: it directs automated validation and local inspection of skill directories. Even if non-malicious, underdescribed operational behavior reduces transparency and can lead to unanticipated file access and execution when the skill is activated.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

This second description-behavior mismatch highlights that the skill does more than provide workflow guidance: it directs automated validation and local inspection of skill directories. Even if non-malicious, underdescribed operational behavior reduces transparency and can lead to unanticipated file access and execution when the skill is activated.

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
86% confidence
Finding

The skill instructs the agent to run local scripts, create directories, validate files, and package archives, but it declares no explicit tool scope or permission boundaries. In a skill system, this increases the chance that the agent will use filesystem, shell, or other powerful capabilities more broadly than the user expected when the skill is triggered.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The trigger description is broad enough that the skill may activate for many requests about creating or updating skills, without clear exclusions for advisory versus operational tasks. Overbroad triggering is dangerous because it can pull in instructions that encourage shell commands, file edits, and packaging steps in contexts where that level of action was not intended.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.