Back to skill

Security audit

skill-creater

Security checks for vulnerabilities and agentic risk

Overview

This is a plausible skill-building helper, but its packaging scripts can accidentally include files outside the intended skill folder.

Review this before installing or running it. Use it only in a dedicated empty workspace, inspect any skill folder for symlinks before packaging, and do not upload generated ZIPs until you have listed their contents and confirmed they contain only the intended skill files.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
package_skill.py:87
Finding

Symbolic Link Traversal Can Include Files Outside the Skill Directory

Content
View full analysis

Vulnerability Details

File Location: package_skill.py:87-94
Vulnerability Type: Archive boundary bypass through symbolic links
Risk Level: Medium

Vulnerable Code:

python
for file_path in path.rglob('*'):
    if file_path.is_file():
        # Skip forbidden files
        if any(f in str(file_path) for f in ['.git', '__pycache__', '.DS_Store', 'node_modules']):
            continue
        
        arcname = file_path.relative_to(path)
        zf.write(file_path, arcname)

Technical Analysis

The packager recursively enumerates entries under the supplied Skill directory and uses Path.is_file() to determine whether each entry should be archived. For symbolic links, is_file() follows the link and returns true when its target is a regular file.

ZipFile.write() subsequently reads the symbolic link target. Although file_path.relative_to(path) produces an archive name within the Skill directory, it does not prove that the resolved source file is within that directory. Consequently, a symlink inside the Skill can point to an arbitrary readable file elsewhere on the host, and the target's contents will be stored under the symlink's internal archive name.

The validation logic does not reject symbolic links and does not compare resolved candidate paths against the resolved Skill root. The forbidden-file substring checks do not provide a reliable boundary control.

Attack Path

  1. An attacker prepares an otherwise valid Skill directory.
  2. The attacker adds a symbolic link inside that directory, such as assets/report.txt, pointing to a sensitive host file.
  3. A victim runs package_skill.py against the untrusted Skill directory.
  4. path.rglob('*') discovers the symlink.
  5. file_path.is_file() follows the symlink and accepts it because its target is a regular file.
  6. zf.write(file_path, arcname) reads the external target and embeds its contents in the ZIP.
  7. The vi ...[truncated 891 chars]
Remediation
View remediation

Remediation Suggestions

  1. Reject symbolic links explicitly during both validation and packaging:

    python
    if file_path.is_symlink():
        raise ValueError(f"Symbolic links are not allowed: {file_path}")
    
  2. Resolve the source root and every candidate, then verify that the resolved candidate remains under the resolved root:

    python
    root = path.resolve()
    
    for file_path in path.rglob("*"):
        if file_path.is_symlink():
            raise ValueError(f"Symbolic links are not allowed: {file_path}")
    
        resolved = file_path.resolve()
        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)
            zf.write(resolved, arcname)
    
  3. Perform the same checks immediately before reading each file to reduce filesystem race risks.

  4. Prefer an allowlist of expected files and top-level directories rather than archiving every recursively discovered file.

  5. Add automated tests covering symlinks to external files, broken symlinks, nested symlinks, and links to forbidden directories.

  6. Inspect the final archive manifest before presenting the package as ready for distribution.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
build.sh:7
Finding

Build Script Packages the Parent Directory Instead of the Skill Root

Content
View full analysis

Vulnerability Details

File Location: build.sh:7-20
Vulnerability Type: Excessive filesystem packaging scope
Risk Level: Medium

Vulnerable Code:

bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.."

SKILL_NAME="skill-craftsmen"
VERSION="1.0.0"
OUTPUT_DIR="./dist"

echo "🔨 Building $SKILL_NAME v$VERSION..."

# Create output directory
mkdir -p "$OUTPUT_DIR"

# Package the skill
python3 scripts/package_skill.py . "$OUTPUT_DIR" "$VERSION"

Technical Analysis

SCRIPT_DIR identifies the directory containing build.sh, which is the Skill root in the audited project. The script then changes into "$SCRIPT_DIR/..", expanding its working scope to the parent directory, and passes . as the source directory to the packager.

The recursive packager therefore operates on the entire parent directory rather than only this Skill. If the parent contains sibling projects, credentials, build artifacts, or other unrelated files, those files may be included in the generated archive.

The script also invokes scripts/package_skill.py, while the audited project contains package_skill.py at its root. In the current directory layout, this mismatch causes the build to fail unless a corresponding script happens to exist in the parent directory's scripts folder. If such a script exists, the command may package the overbroad parent scope as described.

Attack Path

  1. A user places or extracts the Skill into a workspace containing sibling files or projects.
  2. The user executes build.sh.
  3. The script changes from the Skill root to its parent directory.
  4. If scripts/package_skill.py exists at the assumed parent-relative path, the script invokes it with . as the source.
  5. The packager recursively processes the parent workspace instead of the intended Skill directory.
  6. Unrelated files may be included in the generated ZIP.
  7. The archive may then be ...[truncated 918 chars]
Remediation
View remediation

Remediation Suggestions

  1. Keep the build operation anchored to the Skill root.

  2. Invoke the known packager using an absolute path derived from SCRIPT_DIR.

  3. Pass the Skill root explicitly rather than relying on the current working directory.

  4. Place generated archives outside the recursively scanned source, or explicitly exclude the output directory.

  5. Use the following pattern:

    bash
    SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    SKILL_NAME="skill-creater"
    VERSION="1.0.0"
    OUTPUT_DIR="$SCRIPT_DIR/dist"
    
    mkdir -p "$OUTPUT_DIR"
    python3 "$SCRIPT_DIR/package_skill.py" \
        "$SCRIPT_DIR" \
        "$OUTPUT_DIR" \
        "$VERSION"
    
  6. Update the packager to exclude its output directory if output remains inside the source tree.

  7. Add a post-build verification step that lists archive entries and rejects paths not included in an explicit Skill-file allowlist.

  8. Add integration tests that run the build from different working directories and from a workspace containing unrelated sibling files.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
91% confidence
Finding

The declared description overstates the implemented behavior. The code does support template generation for several expected files and can save them to disk, so it is related to skill creation. However, key advertised capabilities are missing: there is no archive/packaging logic and no assets folder creation. Additionally, the executable entrypoint does not generate a complete skill structure from user requirements; it only converts a description into a skill name and prints it. This makes the actual behavior a partial template generator rather than the full ready-to-upload skill packager described.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description presents a skill generator/builder that creates complete AgentSkills from requirements and packages them. The code does not generate content or scaffold directories; it only validates an already existing skill folder and zips it for upload. Packaging is consistent with part of the description, but the primary claimed capability—creating a new skill and its files—is absent. Therefore the declared description materially overstates and misrepresents the actual behavior.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill advertises generation and packaging behavior that implies file reads and writes, but it does not declare any explicit tool scope such as permissions or allowed-tools. In practice, this can cause the agent to operate with ambiguous or overly broad defaults, making unintended filesystem access more likely if the runtime grants tools implicitly.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

An overly broad invocation description can cause the skill to trigger on common requests that only partially match the user's intent. Because this skill is positioned to create files, folders, and archives, accidental activation could lead to unauthorized or confusing workspace modifications, especially in environments where multiple skills compete for routing.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The 'automatic' intent-capture wording makes it unclear when the skill should begin acting versus when it should merely ask clarifying questions. In a meta-skill that may create artifacts and package content, ambiguous activation increases the chance of unintended file generation or workflow hijacking from loosely related prompts.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The generated SKILL.md template hardcodes Chinese text such as trigger examples, scenario descriptions, and notes placeholders. This imposes a specific language/locale on generated skills regardless of user preference, which matches the policy-violation category for language constraints without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file presents core usage and operational instructions partly in Chinese, while the rest of the document is in English, with no indication that language is selected based on user preference. This can effectively force a locale or language presentation style without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The generated user-facing upload guide includes Chinese-only placeholders ('选择合适分类', '复制SKILL.md里的description') in its instructions. This imposes a specific language in the skill output without user opt-in or explanation, which is a natural-language locale policy concern.

Content

No source excerpt is available for this finding.