Back to skill

Security audit

displayname-wk

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate skill-authoring helper, but its helper scripts can read or write outside the intended skill folder in edge cases, so it should be reviewed before installation.

Install only if you trust the skill directories you will initialize or package. Avoid packaging untrusted skill folders, inspect for symlinks before packaging, and use simple hyphen-case skill names until the helper scripts validate paths and reject symlinks.

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:196
Finding
Path Traversal Allows Skill Initialization Outside the Intended Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/init_skill.py`, lines 196-255 **Vulnerability Type**: Unvalidated path component leading to arbitrary directory creation and file writes **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: # Create scripts/ directory with example script 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) print("✅ Created scripts/example.py") # Create references/ directory with example reference doc 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)) print("✅ Created references/api_reference.md") # Create assets/ directory with example asset placeholder assets_dir = skill_dir / 'assets' assets_dir.mkdir(exist_ok=True) example_asset = assets_dir / 'example_asset.txt' ...[truncated 2584 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, 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 not skill_dir.is_relative_to(base_dir): raise ValueError("Skill directory escapes the requested output directory") ``` 4. Apply the same validation inside `init_skill()` rather than relying only on command-line parsing, because the function may be imported and called directly. 5. Create files with explicit, conservative permissions and only make generated scripts executable when that behavior is required. 6. Add regression tests covering `../name`, absolute paths, nested paths, repeated hyphens, path separators, and valid hyphen-case names. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/package_skill.py:69
Finding
Symlink Following During Packaging Can Disclose Local Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/package_skill.py`, lines 69-76 **Vulnerability Type**: Unrestricted symlink following during recursive archive creation **Risk Level**: Medium ### 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 packaging loop recursively processes every path beneath the supplied skill directory. It does not reject symbolic links or resolve each candidate and verify that its target remains inside `skill_path`. For a symbolic link that points to a regular file, `Path.is_file()` follows the link and returns true. `ZipFile.write()` subsequently opens the linked target and stores its contents in the generated archive under the symlink's apparent path. The validator only examines `SKILL.md` frontmatter and does not inspect resource files for links or enforce archive containment. This creates a local file disclosure condition when an untrusted or attacker-modifiable skill directory is packaged. ### Attack Path 1. An attacker creates or modifies an otherwise valid skill directory. 2. The attacker places a symbolic link within the directory, such as: ```bash ln -s /home/user/.ssh/id_rsa malicious-skill/assets/example_asset.txt ``` 3. The victim or an automated agent runs the documented packaging command: ```bash python scripts/package_skill.py malicious-skill ./dist ``` 4. `rglob()` discovers the symbolic link. 5. `is_file()` follows the link and treats its target as a regular file. 6. `zipf.write()` reads the target using the packager's operati ...[truncated 801 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject symbolic links explicitly before calling `is_file()` or `ZipFile.write()`: ```python if file_path.is_symlink(): raise ValueError(f"Symbolic links are not allowed: {file_path}") ``` 2. Resolve every candidate and verify that it remains inside the resolved skill directory: ```python 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_path.resolve(strict=True) if not resolved.is_relative_to(root): raise ValueError(f"Path escapes skill directory: {file_path}") if resolved.is_file(): arcname = resolved.relative_to(root.parent) zipf.write(resolved, arcname) ``` 3. Reject special filesystem objects such as sockets, devices, and named pipes. 4. Consider packaging only explicitly permitted regular files and directories rather than recursively accepting all content. 5. Ensure the output archive is outside the source directory to prevent accidental self-inclusion in later runs. 6. Add tests involving links to files outside the skill, links to directories, broken links, nested links, and ordinary in-tree files. 7. Where supported, perform file opening with no-follow semantics and verify file identity after opening to reduce time-of-check/time-of-use race exposure. ]]>
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
97% confidence
Finding
The declared purpose describes an instructional or guidance-oriented skill for creating or updating skills. The actual code does not provide guidance content or creation assistance; instead, it implements a packaging tool that validates an existing skill directory and compresses it into a distributable .skill file. This is a materially different primary purpose. The filesystem reads/writes and archive creation are consistent with packaging behavior but are not reflected in the declared description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents this as a guide for creating effective skills, implying instructional or workflow assistance for authoring/updating skills. The supplied code instead implements a minimal validation utility: it reads a specified skill directory, checks for SKILL.md, parses YAML frontmatter, enforces allowed properties and required fields, and validates naming/description constraints. This is a materially different primary purpose. While validation could be a supporting part of skill creation, the code chunk itself is specifically a validator rather than a guide, so the description does not accurately represent the actual behavior.

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
95% 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 a wide trigger scope without concrete boundaries or exclusions. It does not provide negative examples or tighter constraints, increasing the chance of unintended invocation for generic conversations about skills.

Static analysis

No suspicious patterns detected.