Back to skill

Security audit

skill-creator

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly purpose-aligned for creating skills, but its helper scripts have filesystem containment gaps that could write outside the intended folder or package unintended local files.

Install only if you are comfortable with a skill that helps agents create and modify other skills. Run the included scripts on trusted skill names and trusted skill folders, inspect generated diffs before using or publishing them, and avoid packaging untrusted directories until symlink and path-containment checks are added.

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:200
Finding
Unvalidated Skill Name Allows Path Traversal and Filesystem Writes Outside the Output Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/init_skill.py:200-246`, with unvalidated command-line input at `scripts/init_skill.py:288-289` **Vulnerability Type**: Path traversal and insufficient input validation **Risk Level**: Medium ### Vulnerable Code ```python def init_skill(skill_name, path): # 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) ``` The command-line values are passed directly to this function: ```python skill_name = sys.argv[1] path = sys.argv[3] result = init_skill(skill_name, path) ``` ### Technical Analysis The command-line help states that `skill_name` must be a kebab-case identifier, but the implementation does not enforce that requirement before using the value as a path component. The expression `Path(path).resolve() / skill_name` does not g ...[truncated 2068 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate `skill_name` before performing any filesystem operation. Enforce the documented format and length: ```python import re if not isinstance(skill_name, str): raise ValueError("Skill name must be a string") if len(skill_name) > 64 or not re.fullmatch( r"[a-z0-9]+(?:-[a-z0-9]+)*", skill_name, ): raise ValueError( "Skill name must be a kebab-case identifier of at most 64 characters" ) ``` 2. Explicitly reject absolute paths, path 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 relative path component") ``` 3. Resolve the final destination and verify containment beneath the base directory: ```python base_dir = Path(path).resolve() skill_dir = (base_dir / skill_name).resolve() if not skill_dir.is_relative_to(base_dir): raise ValueError("Skill destination escapes the requested output directory") ``` 4. Apply validation in both the CLI entry point and `init_skill()` so that library callers cannot bypass it. 5. Create files with restrictive permissions and avoid making generated placeholder scripts executable unless execution is required. 6. Add regression tests covering absolute names, `../`, nested path components, leading or trailing hyphens, consecutive hyphens, and names longer than 64 characters. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/package_skill.py:67
Finding
Skill Packaging Follows Symbolic Links and Can Disclose Files Outside the Skill Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/package_skill.py:67-73` **Vulnerability Type**: Symbolic-link traversal and unintended 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 packaging loop recursively selects entries for which `Path.is_file()` returns true. That check follows symbolic links. The implementation does not call `is_symlink()`, resolve each candidate, or verify that the resolved target remains inside the resolved Skill directory. When a symbolic link inside the Skill points to a readable regular file outside the Skill directory, `zipfile.ZipFile.write()` opens the referenced target. Its contents can consequently be stored in the generated `.skill` archive under the symbolic link's path within the package. Pre-packaging validation does not mitigate this issue because `quick_validate.py` only validates `SKILL.md` frontmatter and does not inspect other files or symbolic links. ### Attack Path 1. An attacker provides or modifies a Skill directory containing a symbolic link to a sensitive readable file outside that directory. For example: ```bash ln -s "$HOME/.config/example/credentials.json" \ untrusted-skill/references/credentials.json ``` 2. The attacker persuades a user or agent to run the documented packaging command: ```bash scripts/package_skill.py untrusted-skill ./dist ``` 3. Validation succeeds if `SKILL.md` contains acceptable frontmatter. 4. `rglob()` discovers the symbolic link, and `is_file()` treats it as a file because its target is a regular f ...[truncated 967 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject symbolic links explicitly before checking 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 allowed: {file_path}") if not file_path.is_file(): continue ``` 2. Resolve every archive candidate and enforce containment within the resolved Skill root: ```python skill_root = skill_path.resolve() for file_path in skill_path.rglob("*"): if file_path.is_symlink(): raise ValueError(f"Symbolic links are not allowed: {file_path}") resolved_file = file_path.resolve(strict=True) if not resolved_file.is_relative_to(skill_root): raise ValueError(f"File escapes skill directory: {file_path}") if not resolved_file.is_file(): continue arcname = file_path.relative_to(skill_path.parent) zipf.write(resolved_file, arcname) ``` 3. Prefer packaging only regular files discovered through a traversal mechanism that does not follow symbolic links. 4. Extend validation to inspect the complete Skill tree and fail on symbolic links, sockets, devices, FIFOs, and other non-regular entries. 5. If the output directory may be inside the source tree, explicitly exclude the output archive to prevent it from being recursively included or producing unexpected package contents. 6. Add automated tests using: - A symlink to a file outside the Skill directory. - A broken symlink. - A symlink to a directory. - A normal file inside the Skill directory. - An output archive located inside the source directory. ]]>
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
99% confidence
Finding
The declared purpose omits that the skill performs structured validation and filesystem inspection of local skill folders and SKILL.md content. Even if these actions are legitimate, hiding operational behavior behind a broad 'guide' description creates a transparency gap that can lead to unauthorized file access or execution in automated settings.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared purpose omits that the skill performs structured validation and filesystem inspection of local skill folders and SKILL.md content. Even if these actions are legitimate, hiding operational behavior behind a broad 'guide' description creates a transparency gap that can lead to unauthorized file access or execution in automated settings.

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
91% confidence
Finding
The skill explicitly instructs the agent to create and edit skill files, run initialization scripts, and package outputs, which is self-modification or agent-environment modification behavior. In a skill system, allowing a skill to author or alter other skills can enable persistence, privilege creep, or insertion of unsafe instructions into future agent runs.

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
90% confidence
Finding
This section directs the agent to update SKILL.md and delete unneeded files, which is direct modification of agent-executable configuration/instruction artifacts. Because SKILL.md governs future behavior, this creates a pathway for persistent changes that may alter agent actions beyond the current session.

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
76% confidence
Finding
The skill instructs the agent to run local scripts, create directories, delete files, and package archives, but it declares no explicit tool scope or permission boundaries. In an environment where skills may gain operational capabilities, this increases the risk of unintended filesystem or command execution beyond what a user expects from a 'guide' skill.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The description says the skill should be used when users want to create or update any skill that extends Claude's capabilities, which is a very wide activation scope. It does not provide negative examples or clear constraints distinguishing when this skill should trigger versus other skill-development or coding skills.

Static analysis

No suspicious patterns detected.