Back to skill

Security audit

skill-creator

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a coherent skill-authoring helper, but its bundled scripts have filesystem containment gaps that users should review before installation.

Install only if you are comfortable with a skill that can create local skill folders and package archives. Use trusted skill names and trusted source directories, avoid packaging untrusted skill trees or trees containing symlinks, and review generated archive contents before sharing.

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:194
Finding
Skill Name Path Traversal Allows Writes Outside the Requested Destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/init_skill.py`, lines 194-221 **Vulnerability Type**: Path traversal and insufficient path validation **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 ``` ### Technical Analysis The script accepts `skill_name` directly from the command line and appends it to the resolved output path without validating that it is a single safe path component. Although the CLI help states that skill names must contain only lowercase letters, digits, and hyphens, this requirement is not enforced. Consequently: - A value containing `../` can traverse outside the requested `--path` directory. - An absolute path can cause `pathlib` to discard the intended base directory. - Nested path separators can create files in unintended subdirectories. The script subsequently creates the computed directory and writes `SKILL.md` and example resources into it. The existing-directory check limits direct overwriting, but it does not prevent creation of a new directory outside the authorized destination. ### Attack Path 1. An attacker or untrusted automation supplies a malicious skill name, such as `../outside-skill` ...[truncated 1079 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate `skill_name` before performing any filesystem operation: ```python if not re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", skill_name): raise ValueError("Invalid skill name") ``` 2. Explicitly reject absolute paths, separators, and special path components: ```python candidate_name = Path(skill_name) if candidate_name.is_absolute() or len(candidate_name.parts) != 1: raise ValueError("Skill name must be a single path component") ``` 3. Resolve the final destination and enforce containment beneath the base directory: ```python base_dir = Path(path).resolve() skill_dir = (base_dir / skill_name).resolve() if skill_dir.parent != base_dir: raise ValueError("Skill path escapes the output directory") ``` 4. Apply the same validation inside `init_skill()` rather than relying only on CLI parsing, because the function may also be imported and called programmatically. 5. Add regression tests covering `../name`, absolute paths, embedded separators, empty names, leading or trailing hyphens, and consecutive hyphens. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/package_skill.py:69
Finding
Skill Packaging Follows File Symlinks and Can Disclose Files Outside the Skill Root<![CDATA[ ## Vulnerability Details **File Location**: `scripts/package_skill.py`, lines 69-75 **Vulnerability Type**: Symlink traversal and unintended local-file disclosure **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 discovers entries under the skill directory and uses `Path.is_file()` to decide whether to archive them. `is_file()` follows symbolic links, so a symlink located inside the skill directory can be treated as a normal file when its target is a file. `zipfile.ZipFile.write()` then opens the supplied path and reads the target contents. The code does not: - Reject symbolic links. - Resolve each file and confirm that its target remains inside `skill_path`. - Use no-follow file-opening semantics. - Warn the user that the package contains files reached through symlinks. As a result, an untrusted skill tree can contain a file symlink pointing to any caller-readable local file, and the target's contents can be copied into the resulting `.skill` archive. ### Attack Path 1. An attacker prepares a skill directory that passes the metadata validator. 2. The attacker adds a file symlink inside the skill tree whose target is a sensitive file outside that tree. 3. A victim invokes the documented packaging command on the untrusted skill directory. 4. `rglob()` discovers the symlink and `is_file()` follows it. 5. `zipf.write()` reads the external target and stores its contents under the symlink's relative archive name. 6. The victim distributes or uploads the generated `.skill` archive, unintentionally disclosing ...[truncated 484 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject all symbolic links during packaging: ```python for file_path in skill_path.rglob("*"): if file_path.is_symlink(): raise ValueError(f"Symbolic links are not permitted: {file_path}") if file_path.is_file(): ... ``` 2. Resolve every candidate and verify that it remains beneath the resolved skill root: ```python root = skill_path.resolve() for file_path in skill_path.rglob("*"): resolved = file_path.resolve(strict=True) try: resolved.relative_to(root) except ValueError: raise ValueError(f"File escapes skill root: {file_path}") ``` 3. Prefer rejecting symlinks even when their current targets are inside the root. This avoids time-of-check/time-of-use races and makes package contents deterministic. 4. Where supported, open source files using no-follow semantics and add them through `ZipFile.writestr()` rather than allowing `zipfile.write()` to reopen paths after validation. 5. Add automated tests for symlinks targeting files both inside and outside the skill root, broken symlinks, and symlink replacement during packaging. ]]>
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 (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose describes an instructional or guidance-oriented skill for creating or updating skills. The supplied code does not provide guidance content or creation workflows; instead, it is an operational packaging utility that validates an existing skill folder and produces a distributable .skill file. This is a materially different primary purpose. The filesystem reads/writes and archive creation are also undeclared capabilities relative to the description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description says this skill is a guide for creating or updating skills. The supplied code instead implements a quick validator that reads files from disk and validates SKILL.md frontmatter and formatting rules. While validation could be tangentially related to skill creation, the primary behavior here is automated linting/verification, not guidance or workflow support for authoring skills. No dangerous extra permissions are present, but the core function is materially different from the declared purpose.

Self-Modification

High
Category
Rogue Agent
Content
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
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.

Self-Modification

High
Category
Rogue Agent
Content
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.
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.

Self-Modification

High
Category
Rogue Agent
Content
# 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")
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.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The description says the skill should be used when users want to create a new skill or update an existing skill, which is expansive and lacks negative examples or scope constraints. Because frontmatter description is the primary trigger, this broad phrasing could cause unintended invocation for loosely related conversations about capabilities or workflow design.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs the agent to run initialization scripts that create directories and example files, but it does not require user confirmation or clearly warn about filesystem modification. In an agentic environment, this can lead to unexpected writes, clutter, overwriting of nearby files, or execution of local scripts without the user's informed consent.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The packaging workflow creates distributable archives and may write artifacts to default or user-specified locations, but the skill gives no user-facing warning about outputs, overwrites, or disk effects. This can cause accidental artifact creation, confusion about where files were written, or unintended disclosure if packaged content is later shared.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The usage text states that skill names must be lowercase, hyphen-case, limited to 40 characters, and match the directory name exactly. However, after reading argv, the code passes the provided skill name directly into path construction and file generation without any validation, so the documented restrictions are not actually implemented.

Static analysis

No suspicious patterns detected.