Back to skill

Security audit

Skill Creator Pro

Security checks for vulnerabilities and agentic risk

Overview

This skill is coherent for creating and testing other skills, but several helper tools can affect local processes or expose local/evaluation data in ways users should review first.

Review this before installing, especially if you will evaluate skills from untrusted authors. Avoid running the viewer with elevated privileges, prefer static output where possible, check that port 3117 is not used before starting the server, inspect skill directories for symlinks before packaging, and do not send proprietary or secret-containing skill/eval content through the description optimizer unless that external Claude CLI use is acceptable.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • 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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
eval-viewer/generate_review.py:272
Finding

Stored Script Injection Through Unsafe JSON Embedding in Review Pages

Content
View full analysis
` element in `viewer.html`. JSON string escaping is not sufficient for embedding data inside an HTML script element. In particular, `json.dumps()` does not escape the HTML parser-sensitive sequence ``. If an untrusted prompt, generated output, grading result, previous feedback value, or benchmark field contains this sequence, the browser terminates the surrounding script element regardless of whether the sequence occurs inside a JavaScript string. An attacker-controlled value can therefore inject a new script element, for example: ```html ``` This is especially relevant because the viewer is explicitly intended to process artifacts produced by evaluated Skills and agents. Those artifacts must be treated as untrusted. ### Attack Path 1. An attacker supplies or influences a Skill being evaluated. 2. The Skill writes an output file or grading-related value containing a `` payload. 3. `generate_review.py` reads the malicious content and places it in the `runs` or related embedded data structure. 4. `json.dumps()` preserves the dangerous HTML closing-tag sequence. 5. `generate_html()` inserts the serialized v ...[truncated 1167 chars]
Remediation
View remediation
``` 3. Before embedding JSON in HTML, escape at least the HTML-sensitive characters: ```python data_json = ( json.dumps(embedded) .replace("<", "\\u003c") .replace(">", "\\u003e") .replace("&", "\\u0026") .replace("\u2028", "\\u2028") .replace("\u2029", "\\u2029") ) ``` 4. Add a restrictive Content Security Policy. Prefer a nonce or hash for trusted scripts and disallow arbitrary inline execution. 5. Avoid loading external resources unless necessary. If network access is not required, use a policy such as `connect-src 'self'` and bundle required assets locally. 6. Add regression tests using payloads containing ``, nested tags, Unicode separators, and event-handler markup. 7. Treat every prompt, output file, grading field, benchmark field, and feedback value as attacker-controlled. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
eval-viewer/generate_review.py:288
Finding

Viewer Startup Terminates Unrelated Processes Listening on the Selected Port

Content
View full analysis
None: """Kill any process listening on the given port.""" try: result = subprocess.run( ["lsof", "-ti", f":{port}"], capture_output=True, text=True, timeout=5, ) for pid_str in result.stdout.strip().split("\n"): if pid_str.strip(): try: os.kill(int(pid_str.strip()), signal.SIGTERM) except (ProcessLookupError, ValueError): pass if result.stdout.strip(): time.sleep(0.5) except subprocess.TimeoutExpired: pass except FileNotFoundError: print("Note: lsof not found, cannot check if port is in use", file=sys.stderr) ``` The function is called unconditionally before starting the server: ```python # Kill any existing process on the target port port = args.port _kill_port(port) handler = partial( ReviewHandler, workspace, skill_name, feedback_path, previous, benchmark_path, ) try: server = HTTPServer(("127.0.0.1", port), handler) except OSError: server = HTTPServer(("127.0.0.1", 0), handler) port = server.server_address[1] ``` ### Technical Analysis The viewer invokes `lsof` to identify every process listening on the selected port and sends `SIGTERM` to each returned process. It does not verify that the process is a previous instance of this viewer, confirm process ownership or command identity, or ask the user for approval. The default port is fixed at `3117`, so an unrelated application legitimately using that port can be terminated merely by starting the review viewer. Port discovery is sufficient; terminating an unknown listener is not necessary for the declared review functionality because the impl ...[truncated 1515 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/package_skill.py:96
Finding

Skill Packaging Follows Symbolic Links and Can Archive Files Outside the Skill Directory

Content
View full analysis
/home/user/.config/service/credentials.json ``` 2. The directory otherwise contains a valid `SKILL.md`, allowing validation to succeed. 3. The user runs: ```bash python -m scripts.p ...[truncated 1159 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Warning
Location
scripts/improve_description.py:21
Finding

Untrusted Skill Instructions Are Passed to a Tool-Capable Claude Process Without Isolation

Content
View full analysis
str: """Run `claude -p` with the prompt on stdin and return the text response.""" cmd = ["claude", "-p", "--output-format", "text"] if model: cmd.extend(["--model", model]) env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"} result = subprocess.run( cmd, input=prompt, capture_output=True, text=True, env=env, timeout=timeout, ) if result.returncode != 0: raise RuntimeError( f"claude -p exited {result.returncode}\nstderr: {result.stderr}" ) return result.stdout ``` The complete Skill body is inserted directly into the optimization prompt: ```python prompt += f""" Skill content (for context on what the skill does): {skill_content} Based on the failures, write a new and improved description that is more likely to trigger correctly. When I say "based on the failures", it's a bit of a tricky line to walk because we don't want to overfit to the specific cases you're seeing. So what I DON'T want you to do is produce an ever-expanding list of specific queries that this skill should or shouldn't trigger for. Instead, try to generalize from the failures to broader categories of user intent and situations where this skill would be useful or not useful. The reason for this is twofold: 1. Avoid overfitting 2. The list might get loooong and it's injected into ALL queries and there might be a lot of skills, so we don't want to blow too much space on any given description. Concretely, your descript ...[truncated 4004 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description centers on skill authoring, editing, optimization, and running evals on skills. This code does not create or modify skills, optimize descriptions, or execute evals. Instead, it implements an eval-review web viewer for existing workspace results, including file discovery, HTML generation, local serving, benchmark display, and persistence of human feedback. While review of eval outputs is adjacent to skill evaluation, the primary purpose is materially narrower and different: viewing and annotating eval results, not building or improving skills directly. It also performs undeclared operational capabilities such as launching a web server, opening a browser, writing feedback files, and terminating processes on a port.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

There is a clear mismatch between the declared purpose and the actual code behavior. The description claims the skill is for authoring, improving, and evaluating skills, including eval-driven iteration and trigger optimization. However, the supplied code only validates a skill directory and packages it into a .skill file. Its primary purpose is distribution/build packaging, not creation, modification, optimization, or evaluation of skill quality. While validation is loosely related to skill management, the main functionality is materially different from the declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a broad skill authoring and evaluation capability: creating skills, editing or optimizing them, running evals, and benchmarking performance. The supplied code does none of those things. It only performs static validation of a skill's SKILL.md frontmatter and naming/length rules. While validation could be a supporting utility within a larger skill-development workflow, this code chunk's actual primary purpose is narrow format validation, which is materially different from the declared end-to-end creation/improvement/evaluation behavior.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger guidance is intentionally broad, including generic phrases like making, improving, testing, or optimizing a skill, and encourages invocation from many loosely defined contexts. In a high-capability skill with shell, file, eval, packaging, and process-management behaviors, over-triggering increases the chance it activates in situations where a narrower, safer skill or direct assistance would be more appropriate.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 394)May include surrounding context.

md
1. Read the template from `assets/eval_review.html`

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The helper unconditionally finds any PID listening on the requested port and sends SIGTERM, regardless of whether the process belongs to this tool. That can disrupt unrelated local services, developer tools, databases, or security-sensitive software, creating a denial-of-service condition on the host when the script is run.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/improve_description.py (reported line 33)May include surrounding context.

python
# Remove CLAUDECODE env var to allow nesting claude -p inside a
    # Claude Code session. The guard is for interactive terminal conflicts;
    # programmatic subprocess usage is safe. Same pattern as run_eval.py.
    env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}

    result = subprocess.run(
        cmd,

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/run_eval.py (reported line 83)May include surrounding context.

python
# Remove CLAUDECODE env var to allow nesting claude -p inside a
    # Claude Code session. The guard is for interactive terminal conflicts;
    # programmatic subprocess usage is safe. Same pattern as run_eval.py.
    env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}

    result = subprocess.run(
        cmd,

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
85% confidence
Finding

The script intentionally discovers a parent project root by locating .claude/ and then writes a temporary command file into that agent configuration directory. In the context of an eval tool, this modifies trusted agent-discovery state and could affect or poison other Claude runs in the same project if cleanup fails or concurrent runs collide, making it more sensitive than ordinary temp-file usage.

Content

Scanner excerpt · scripts/run_eval.py (reported line 23)May include surrounding context.

python
def find_project_root() -> Path:
    """Find the project root by walking up from cwd looking for .claude/.

    Mimics how Claude Code discovers its project root, so the command file
    we create ends up where claude -p will look for it.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs use of shell commands, filesystem reads/writes, environment-dependent tooling, and process control, but it does not declare any explicit tool scope or allowed-tools boundary. In a skill that can create, run, and package other skills, missing scope makes unintended or overly privileged execution easier and weakens reviewability of what the skill is permitted to do.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The instruction to make descriptions 'pushy' systematically biases generated skills toward vague or overly expansive trigger conditions. Because this skill is itself a skill generator, that pattern can propagate broad auto-invocation behavior into downstream skills, multiplying the operational and security risk of accidental use of powerful capabilities.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
81% confidence
Finding

Using nohup to launch a background viewer introduces session persistence beyond the immediate interaction and can leave long-lived processes serving local content after the task is complete. In this skill's context, that persisted process may continue exposing review artifacts or consume resources if cleanup fails or is skipped.

Content

Scanner excerpt · SKILL.md (reported line 268)May include surrounding context.

  1. Launch the viewer with both qualitative outputs and quantitative data:
    bash
    nohup python <skill-creator-path>/eval-viewer/generate_review.py \
      <workspace>/iteration-N \
      --skill-name "my-skill" \
      --benchmark <workspace>/iteration-N/benchmark.json \
    

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Lines L189-L191 state that when analyzing benchmark results, the analyzer's purpose is only to surface patterns and anomalies and not suggest skill improvements. This contradicts the enclosing skill's documented purpose of improving and optimizing skills through eval-driven iteration, creating an intent mismatch in the skill documentation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · eval-viewer/generate_review.py (reported line 291)May include surrounding context.

python
def _kill_port(port: int) -> None:
    """Kill any process listening on the given port."""
    try:
        result = subprocess.run(
            ["lsof", "-ti", f":{port}"],
            capture_output=True, text=True, timeout=5,
        )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The main flow invokes the port-killing routine automatically before server startup, with no warning or consent. In a skill meant to create and iterate on other skills, users may run this utility routinely, increasing the chance of accidentally terminating unrelated local applications and causing avoidable workflow disruption or data loss.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest describes a skill for creating, editing, and evaluating skills, including optimizing descriptions. While using an LLM to generate text is consistent with that purpose, this implementation does so by spawning an external subprocess and inheriting nearly the full environment, which is a broader execution capability than the manifest suggests. That subprocess boundary can expose ambient credentials or system-level behavior not implied by a description-optimization tool.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/improve_description.py (reported line 35)May include surrounding context.

python
# programmatic subprocess usage is safe. Same pattern as run_eval.py.
    env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}

    result = subprocess.run(
        cmd,
        input=prompt,
        capture_output=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script sends full skill content, eval results, and history to an external model process without any consent gate, redaction, or warning at the point of transfer. If SKILL.md or eval artifacts contain secrets, proprietary logic, or sensitive user data, this creates an unintended data-exposure path to the external model backend.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/run_eval.py (reported line 85)May include surrounding context.

python
# programmatic subprocess usage is safe.
        env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}

        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest describes functionality around skill creation, modification, optimization, and eval-driven measurement. Automatically launching a browser is not necessary to perform those tasks and introduces an OS-level side effect outside the core scope of skill improvement.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The instructions require writing grading.json to {outputs_dir}/../grading.json, which explicitly directs the agent to modify a file outside the designated output directory boundary. If outputs_dir is attacker-controlled or unexpectedly resolved, this can enable unintended file writes to sibling locations and weakens containment assumptions for the grader.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This is a code file, so missing-warning checks apply to safety-relevant file operations. The script performs file writes to user-specified or default output paths, but there is no confirmation prompt or explicit overwrite warning before writing, which could silently replace existing benchmark artifacts.

Content

No source excerpt is available for this finding.