Back to skill

Security audit

Skill Creator

Security checks for vulnerabilities and agentic risk

Overview

The skill is broadly coherent as a skill-building helper, but several bundled tools can expose local data or disrupt local processes in ways users may not expect.

Install only if you are comfortable giving this skill broad local development authority. Avoid packaging untrusted skill directories unless symlinks are removed or the packager is fixed, prefer static review output over the background server, and do not run the viewer on sensitive eval outputs until the script-embedding issue is addressed.

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 (3)

T09 · Insecure Skill Coding Practices

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

Stored Script Injection in Generated Review Pages

Content
View full analysis
` element in `viewer.html`. JSON string encoding does not make data safe for placement inside an HTML script element. In particular, it does not neutralize the HTML closing sequence ``. If attacker-controlled review data contains a payload such as: ```html ` breakout payload. 3. `embed_file()` reads that output and includes it in the `embedded` data structure. 4. `generate_html()` serializes the structure and inserts it directly into the executable script context. 5. The user opens the generated static review page or the locally served viewer. 6. The browser parses and executes the injected JavaScript. 7. The payload can read embedded prompts, outputs, grades, benchmark data, and other inf ...[truncated 944 chars]
Remediation
View remediation
``` Before embedding it, escape at least `<`, `>`, `&`, U+2028, and U+2029. For example, replace `<` with `\u003c` so `` cannot be recognized by the HTML parser. 3. Alternatively, Base64-encode the complete JSON document, place only the Base64 alphabet in the page, and decode and parse it as data at runtime. 4. Add a restrictive Content Security Policy. Prefer a nonce- or hash-based `script-src` policy and disallow arbitrary inline scripts. 5. Avoid dynamically constructing HTML where DOM APIs and `textContent` can be used. 6. Add regression tests containing: - `` - Mixed-case closing tags. - HTML comments and malformed script-closing sequences. - Payloads in prompts, text outputs, grading evidence, benchmark notes, and previous feedback. 7. Treat every evaluated output as untrusted, even when it was generated locally. ]]>

T05 · Unauthorized Access and Privilege Escalation

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

Automatic Termination of Unrelated Processes Listening on the Viewer 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 invoked unconditionally during startup: ```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: # Port still in use after kill attempt — find a free one server = HTTPServer(("127.0.0.1", 0), handler) port = server.server_address[1] ``` ### Technical Analysis Before attempting to bind the viewer server, the program runs `lsof` and sends `SIGTERM` to every process reported as listening on the selected port. The implementation does not verify: - Whether the process was started by this project. - Whether it is a previous viewer instance. - Whether the process belongs to the current workspace. - Whether terminating it was authorized by the user. - Whether it holds unsaved state or provides an important local service. This behavior exceeds the minimum privileges required for the viewer. The code ...[truncated 1631 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/package_skill.py:91
Finding

Skill Packaging Follows File Symlinks Outside the Selected Directory

Content
View full analysis
/home/user/.ssh/id_rsa ``` 3. The user follows the documented packaging workflow and runs `scripts.package_skill`. 4. `rglob('*')` discovers the symlink. 5. `is_file()` follows the link and accepts the target as a regular file. 6. `zipf.write()` reads the external ta ...[truncated 936 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 (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill description does not mention packaging and generating distributable .skill archives, yet the body instructs the agent to build and output installable artifacts. This is less severe than direct code execution issues, but it still creates a transparency problem because users may not expect artifact generation and distribution steps from the declared purpose alone.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill description does not mention packaging and generating distributable .skill archives, yet the body instructs the agent to build and output installable artifacts. This is less severe than direct code execution issues, but it still creates a transparency problem because users may not expect artifact generation and distribution steps from the declared purpose alone.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill description does not mention packaging and generating distributable .skill archives, yet the body instructs the agent to build and output installable artifacts. This is less severe than direct code execution issues, but it still creates a transparency problem because users may not expect artifact generation and distribution steps from the declared purpose alone.

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 364)May include surrounding context.

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

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 locates the nearest .claude directory by walking upward from the current working directory, then writes a temporary command file into .claude/commands. In a security-sensitive environment, this modifies agent configuration in the active project context and could affect which skills the downstream agent discovers or uses, making it a real config-scope manipulation risk even though it appears to be for evaluation purposes.

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
89% confidence
Finding

The skill instructs the agent to read and write files, execute shell commands, inspect environment-dependent state, and launch helper scripts, but it does not declare any tool restrictions or allowed-tools scope. In a skill that handles arbitrary user-provided skill content and evaluation artifacts, that omission increases the blast radius of prompt injection or operator mistakes because the agent may use powerful capabilities without explicit least-privilege boundaries.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill spans drafting, editing, testing, benchmarking, description optimization, packaging, and user review workflows, but its invocation boundaries are broad and loosely defined. In practice, ambiguous activation criteria can lead to overuse of a high-capability skill in conversations that do not require shell access, filesystem writes, or long-running evaluation flows.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly recommends making descriptions 'pushy' to counter under-triggering, encouraging broad activation across overlapping user requests. Overbroad trigger guidance can cause the skill to activate in contexts where it gains access to unrelated user content or performs unnecessary file, shell, or evaluation actions, increasing accidental misuse and prompt-surface exposure.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
72% confidence
Finding

The skill instructs the agent to launch a background process with nohup for a review server, which persists beyond the immediate interaction and may continue serving local data until manually terminated. Persistent background services increase the risk of orphaned processes, stale data exposure, and unintended access to workspace artifacts, especially if cleanup is missed or if the server binds broadly.

Content

Scanner excerpt · SKILL.md (reported line 238)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 \
    

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script unconditionally finds and sends SIGTERM to any process listening on the requested port before starting its own server. That creates an unsafe local denial-of-service condition: running the viewer can disrupt unrelated services, developer tooling, or security-sensitive local processes without user confirmation. In a skill-creation/eval workflow, users may run this against shared dev environments or laptops with other services bound to the default port, making the behavior less justified and more dangerous.

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,
        )

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The page loads remote resources from Google Fonts and the SheetJS CDN, which creates a supply-chain and privacy risk because code and metadata are fetched from third parties at runtime. Even with SRI on the SheetJS script, these dependencies can leak usage information, reduce offline integrity, and expand the trust boundary for a local eval-review tool that otherwise does not require network access for core functionality.

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
95% confidence
Finding

The script sends the full prompt—including SKILL.md content, eval results, history, and possibly test/log data—to an external claude -p process without any explicit consent gate, redaction, or warning at the point of transfer. In a skill-development context, those inputs can contain proprietary prompts, customer examples, benchmark queries, or secrets embedded in skill content, creating a real confidentiality and governance risk.

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,

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This markdown skill directs the agent to save structured analysis results to {output_path}, which is a file-writing operation. The description does not include any warning or disclosure about creating or overwriting files, even though writing output can affect user data depending on the path provided.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The benchmark-analysis section instructs the agent to save notes to {output_path} as JSON, which is another file write. The markdown does not warn users that the skill writes files or clarify overwrite expectations, so the behavior is under-disclosed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill instructs the agent to write a JSON results file to a provided path, but it does not require confirmation before overwriting an existing file or constrain the destination to a safe workspace. If an attacker or misconfigured caller supplies a sensitive path, the agent could clobber existing files or modify unintended locations, causing integrity loss or workflow disruption.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The skill instructs the agent to write grading.json to a sibling path relative to outputs_dir, which is a filesystem modification outside the explicitly provided output directory. If outputs_dir is attacker-controlled or unexpectedly resolved (for example via symlinks or path manipulation), the agent could overwrite files outside the intended workspace boundary.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code performs file writes to user-specified or default paths, but there is no confirmation prompt or pre-write warning about overwriting existing files. Although the script prints messages after generation and its purpose is aggregation, users are not clearly warned before the write occurs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script automatically opens a browser window for the generated report via webbrowser.open() without an explicit confirmation step. While this is not typically a severe security flaw, it can cause unexpected local side effects, trigger external browser handlers, or be abused in automated/headless environments where opening local or registered URLs is undesirable.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.