Back to skill

Security audit

OpenClaw-Skill-Creator

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent skill-creation purpose, but it runs authenticated agent processes and bundled review tools with several under-scoped security risks.

Use this only in an isolated workspace with non-sensitive skills and eval prompts. Avoid running run_eval.py, run_loop.py, or improve_description.py with real secrets, proprietary code, or untrusted eval sets unless you have sandboxed the claude CLI and environment. Prefer static review output, do not let it kill existing services, and inspect packaged skill directories for symlinks before distributing them.

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

T09 · Insecure Skill Coding Practices

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

Script-context injection in the evaluation review viewer

Content
View full analysis
// ---- Embedded data (injected by generate_review.py) ---- /*__EMBEDDED_DATA__*/ ``` ### Technical Analysis The embedded structure can contain attacker-controlled evaluation prompts, grading evidence, feedback, and output-file contents. Although `json.dumps()` produces valid JSON, it does not make that JSON safe for direct placement inside an HTML `` terminates the script element even when it appears inside a JavaScript string literal. Consequently, a malicious output containing a payload such as: ```html ``` can break out of the embedded JSON and execute as JavaScript when the generated review page is opened. The viewer does not define a restrictive Content Security Policy. It also loads an external JavaScript dependency, so browser-side compromise can access all data embedded in the page and initiate outbound requests. ### Attack Path 1. A malicious or compromised Skill is evaluated. 2. The Skill writes a text output, prompt, or grading value containing a `` breakout payload. 3. `generate_review.py` reads the value and serializes it with `json.dumps()`. 4. Th ...[truncated 1109 chars]
Remediation
View remediation
SAFE_JSON ``` - Before embedding JSON into HTML, escape at least `<`, `>`, `&`, U+2028, and U+2029. For example, replace `<` with `\u003c`. - Prefer a well-tested HTML-safe JSON serialization routine instead of ad hoc string replacement. - Add a restrictive Content Security Policy that blocks inline and unauthorized external scripts. - Add regression tests using values containing ``, HTML event handlers, Unicode separators, and nested script elements. - Treat every field read from an evaluated workspace as untrusted, regardless of file extension. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
assets/eval_review.html:54
Finding

Raw placeholder replacement permits JavaScript and HTML injection in the eval-set review template

Content
View full analysis

Eval Set Review: __SKILL_NAME_PLACEHOLDER__

Current description: __SKILL_DESCRIPTION_PLACEHOLDER__

+ Add Query Export Eval Set
QueryShould TriggerActions

` can therefore terminate the original script element and execute arbitrary JavaScript. Crafted Skill metadata can also inject HTML into the page when raw textual replacement is used. ### Attack Path 1. An untrusted Skill supplies a malicious name or description, or a generated eval query contains a script-break ...[truncated 976 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/package_skill.py:91
Finding

Skill packaging follows symlinks and can archive files outside the Skill directory

Content
View full analysis
/home/user/.config/sensitive-config ``` 3. `quick_validate.py` validates only the Skill frontmatter and accepts the directory. 4. The user runs `scripts/package_skill.py`. ...[truncated 808 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/run_eval.py:70
Finding

Trigger evaluation launches authenticated Claude agents without a least-privilege execution profile

Content
View full analysis
Remediation
View remediation

T01 · Skill Instruction Hijacking

Warning
Location
scripts/improve_description.py:74
Finding

Untrusted Skill content can inject instructions into description optimization

Content
View full analysis
"{current_description}" Current scores ({scores_summary}): """ ``` Later, complete Skill content is interpolated into the same instruction string: ```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. ... Please respond with only the new description text in tags, nothing else.""" text = _call_claude(prompt, model) ``` ### Technical Analysis The optimizer combines trusted instructions and untrusted content in one plain-text prompt. XML-like tags are used only as textual delimiters; they do not enforce an instruction/data boundary. A malicious `SKILL.md`, current description, or eval query can close the apparent delimiter and insert competing instructions. For exampl ...[truncated 1804 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

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

Review viewer startup terminates unrelated processes using 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) ``` It is invoked unconditionally before binding: ```python # Kill any existing process on the target port port = args.port _kill_port(port) ``` ### Technical Analysis The viewer sends `SIGTERM` to every process reported by `lsof` as listening on the selected port. It does not verify: - Whether the process is a previous instance of this viewer. - Whether the process belongs to the current workspace. - Whether the user intended to stop it. - Whether the PID was reused between discovery and termination. Killing an existing listener is unnecessary. The code already has a safer fallback that binds to port `0` if the requested port remains unavailable. A user-controlled `--port` option also allows a caller to target a known local service port deliberately. ### Attack Path 1. A legitimate development server or local service listens on a known port. 2. The viewer is started with that port, either accidentally or through a supplied command. 3. `_kill_port()` runs `lsof` and ...[truncated 785 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (23)

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

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

md
---
name: skill-creator
description: Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
---

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`

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script automatically finds and sends SIGTERM to any process listening on the requested port before starting its server, without user confirmation. In a developer workstation context, this can disrupt unrelated local services or tooling and may cause data loss or denial of service if a critical process is terminated unexpectedly.

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

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

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.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The guidance explicitly encourages 'pushy' descriptions to counter under-triggering, which can cause the skill to activate for adjacent or unintended requests. In an agent ecosystem, overbroad triggering increases the chance that this skill intercepts tasks outside its intended scope and steers execution into file edits, benchmark scripts, subprocesses, or other side-effecting workflows the user did not actually want.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

The skill instructs launching a long-lived background process with nohup, which creates session persistence beyond the immediate interaction. In agent environments, persistent processes can outlive user awareness, continue serving content or consuming resources, and expose generated artifacts until manually terminated.

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 \
    

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The first OpenClaw section says OpenClaw has no subagents and therefore should skip parallel execution, baseline runs, blind comparison, and description optimization because the required tooling is unavailable. A later OpenClaw-specific section states the opposite: that subagents are available and description optimization should work in OpenClaw. These instructions cannot both be true, so the documentation actively contradicts itself about how the skill should be used.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file defines a second, different analyzer role after the first role without clearly stating how the skill decides which mode applies. Because both sections present themselves as authoritative instructions for the same file, the activation condition and scope are ambiguous, which could lead to unintended or inconsistent invocation behavior.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Earlier sections define the analyzer's role as identifying loser weaknesses and producing actionable improvement suggestions. Lines L189-L191 redefine the analyzer's purpose for benchmark analysis as surfacing patterns and anomalies 'not suggest skill improvements,' which directly conflicts with the earlier stated purpose if this file is treated as one skill specification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The docstring for _kill_port says it will 'Kill any process listening on the given port', which understates a materially dangerous side effect: it enumerates all PIDs returned by lsof and sends SIGTERM to each one. This broad process-termination behavior is more aggressive than a benign 'free port' helper and the documentation does not communicate that the tool may kill unrelated local processes.

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

This code accepts POSTed review data and writes it directly to feedback.json, which modifies user workspace contents. Although the module docstring mentions auto-save behavior, the actual write operation has no confirmation prompt, visible user-facing log, or inline warning at the point of persistence.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The page automatically POSTs reviewer-entered feedback to /api/feedback during typing, but the UI does not clearly disclose that text is being transmitted off-page in near real time. Review content may contain sensitive evaluation notes, internal data, or regulated information, so silent autosave over the network creates a privacy and consent issue and can surprise users operating in environments that assume local-only review.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Clicking 'Submit All Reviews' sends the full review set to /api/feedback, but the button text and surrounding UI do not clearly warn that this action performs a network upload rather than a purely local completion step. In a review tool, users may include confidential assessments, so lack of explicit disclosure undermines informed consent and can lead to unintended data exfiltration to the hosting server.

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 constructs a prompt containing full skill content, evaluation queries, prior history, and possibly test results, then sends it to claude -p. If those inputs contain proprietary code, secrets, or sensitive user queries, this creates an external data disclosure channel without any explicit consent gate, minimization, or redaction at the call site.

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,

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

This file is a changelog and contains security guidance about another skill, not executable code. The statements about the replacement skill's safety characteristics are documentary claims that are not substantiated within this file, but they do not directly contradict any code present here because no code exists in the file.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The trigger-eval advice emphasizes broad should-trigger coverage but does not require corresponding exclusion tests to translate into explicit limits in the final description. This can systematically optimize the skill toward aggressive activation, increasing accidental invocation and unnecessary execution of tooling or background processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

This markdown skill description explicitly tells the agent to save results to a JSON file, which is a file-write operation. The document does not include any warning that the skill will create or overwrite a file, which is relevant to user data and system integrity for markdown-scoped warning checks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This markdown skill directs the agent to save results to {outputs_dir}/../grading.json, which is a file write affecting user data or workspace state. The description does not include any warning that the skill will create or overwrite this file, so users may not realize the skill modifies files rather than only reading and evaluating them.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.