Back to skill

Security audit

Skill Maintainer

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent ClawHub portfolio maintenance tool, but it needs review because untrusted skill metadata can influence generated dashboards, AI prompts, and in one opt-in mode local skill file edits.

Install only if you are comfortable reviewing the scripts and running them manually. Avoid --apply-safe unless you have verified each resolved source path, treat generated agent_prompts as containing untrusted metadata, and do not open generated dashboards from untrusted portfolio data until the script-context escaping issue is fixed. Keep real hide, merge, and publish commands behind explicit human review.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/render_dashboard.py:357
Finding

Stored JavaScript Injection in the Generated Dashboard

Content
View full analysis
str: return json.dumps(rows, ensure_ascii=False, separators=(",", ":")) ``` ```python rows_json = render_table_rows(clean_rows) ``` ```html
Remediation
View remediation
... ``` Then parse its `textContent`: ```javascript const rows = JSON.parse(document.getElementById("portfolio-data").textContent); ``` 3. Before embedding JSON in HTML, escape at least `<`, `>`, `&`, U+2028, and U+2029. For example: ```python def html_safe_json(value: Any) -> str: return ( json.dumps(value, ensure_ascii=False, separators=(",", ":")) .replace("&", "\\u0026") .replace("<", "\\u003c") .replace(">", "\\u003e") .replace("\u2028", "\\u2028") .replace("\u2029", "\\u2029") ) ``` 4. Replace `innerHTML` table generation with `document.createElement()`, `textContent`, and explicit attribute assignment. 5. Validate publisher handles and slugs against the exact ClawHub identifier grammar before constructing URLs. 6. Construct links with the `URL` API and allow only `https:` URLs targeting the expected ClawHub hostname. 7. Add regression tests using payloads containing ``, quotation marks, HTML tags, event handlers, and malformed slugs. 8. Consider a restrictive Content Security Policy that disallows inline scripts and limits outbound connections. ]]>

T01 · Skill Instruction Hijacking

Error
Location
scripts/auto_upgrade.py:581
Finding

Prompt Injection Through Untrusted ClawHub Metadata

Content
View full analysis
str: slug = candidate["slug"] source_path = candidate.get("source_path_resolved") or "" findings = "\n".join(f"- {item}" for item in candidate.get("findings", [])) edits = "\n".join(f"- {item}" for item in candidate.get("recommended_edits", [])) validation = "\n".join(f"- `{item}`" for item in candidate.get("validation_commands", [])) acquisition = "\n".join(f"- `{item}`" for item in candidate.get("source_acquisition_commands", [])) source_errors = "\n".join(f"- {item}" for item in candidate.get("source_errors", [])) return f"""Use $skillopt principles to upgrade one ClawHub skill safely. Target skill: {slug} Local source: {source_path or 'MISSING'} Display name: {candidate.get('display_name', '')} Summary: {compact_text(candidate.get('summary'), 500)} Signals: downloads={candidate.get('downloads', '')}, installs={candidate.get('installs_all_time', '')}, stars={candidate.get('stars', '')}, comments={candidate.get('comments', '')}, quality_score={candidate.get('quality_score', '')}, priority={candidate.get('maintenance_priority', '')} Quality reason: {candidate.get('quality_reason', '')} Findings: {findings} Recommended edits: {edits} Source acquisition order: 1. GitHub repository source. 2. Local source roots. 3. ClawHub install/download fallback. Source acquisition commands: {acquisition or '- already resolved locally'} Source errors: {source_errors or '- none'} Rules: - Preserve the original public contract and slug. - Prefer small, reviewable edits to SKILL.md and adjacent metadata only. - Add examples, clearer trigger text, workflow, validation checks, and safety boundaries where missing. - Do not delete, hide, merge, rename, or change ow ...[truncated 3462 chars]
Remediation
View remediation
{...} ``` 4. Minimize prompt inputs. Exclude source errors, raw repository metadata, and other fields unless they are necessary for the specific maintenance decision. 5. Normalize or reject control characters, role markers, XML-like instruction tags, Markdown code-fence escapes, and excessive line breaks. 6. Require the downstream agent to operate within one explicitly approved, canonical local directory. 7. Restrict the downstream agent's tools: - Deny arbitrary network access. - Deny access to credentials and environment files. - Deny real publishing operations. - Permit only an allowlisted validator and dry-run publishing command. 8. Keep human approval outside the generated prompt and enforce it in the execution layer rather than relying solely on natural-language rules. 9. Display remote metadata separately from executable or recommended commands. 10. Add adversarial tests with summaries containing instruction overrides, tool-call requests, encoded instructions, and fake system messages. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/auto_upgrade.py:322
Finding

Remote Source Metadata Can Select Local Skill Files for Modification

Content
View full analysis
dict[str, Any]: path_text = candidate.get("source_path_resolved") if not path_text: return {"applied": False, "reason": "missing source"} path = Path(path_text) skill_md = path / "SKILL.md" if not skill_md.exists(): return {"applied": False, "reason": "missing SKILL.md"} if not candidate.get("safe_auto_editable"): return {"applied": False, "reason": "package is not safe-auto-editable"} text = skill_md.read_text("utf-8", errors="replace") additions: list[str] = [] if not candidate.get("has_examples"): additions.append(example_prompt_block(candidate)) if candidate.get("risk_labels") and not candidate.get("has_boundaries"): additions.append(boundary_block(candidate)) if not additions: return {"applied": False, "reason": "no safe deterministic edit needed"} backup_dir = run_dir / "backups" / candidate["slug"] backup_dir.mkdir(parents=True, exist_ok=True) shutil.copy2(skill_md, backu ...[truncated 2800 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Use `scripts/auto_upgrade.py` when the portfolio is too large to maintain manually. The loop selects the next high-quality skills worth reviewing, inspects loca

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Use `scripts/auto_upgrade.py` when the portfolio is too large to maintain manually. The loop selects the next high-quality skills worth reviewing, inspects loca

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Use `scripts/auto_upgrade.py` when the portfolio is too large to maintain manually. The loop selects the next high-quality skills worth reviewing, inspects loca

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Use `scripts/auto_upgrade.py` when the portfolio is too large to maintain manually. The loop selects the next high-quality skills worth reviewing, inspects loca

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
appends missing example prompts or sensitive-domain safety boundaries to local `SKILL.md` files when the package has no forbidden files and a small file surface

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
appends missing example prompts or sensitive-domain safety boundaries to local `SKILL.md` files when the package has no forbidden files and a small file surface

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/auto_upgrade.py (reported line 37)May include surrounding context.

python
DATA_UNAVAILABLE = "data_unavailable"

FORBIDDEN_PACKAGE_NAMES = {
    ".env",
    ".DS_Store",
    "node_modules",
    "dist",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill instructs use of shell commands, file access, and network-dependent workflows, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an authorization ambiguity where an agent/runtime may expose broader capabilities than intended, increasing the chance of unintended command execution, filesystem modification, or external access during maintenance operations.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The default prompt is broadly phrased and covers multiple loosely bounded actions such as finding skills, generating plans, and handling publish gating. In systems that support prompt-based or semantic skill routing, this can cause the skill to be invoked for general maintenance, analytics, or publishing-related requests even when the user did not explicitly intend to use it, increasing the chance of overreach into sensitive portfolio or publishing workflows.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Enabling implicit invocation without additional narrowing conditions allows the platform to auto-select this skill based on broad semantic similarity. Because this skill touches maintenance planning, dashboards, published skills, and approval-gated publish actions, unintended activation could expose portfolio data, generate risky recommendations, or steer workflows toward sensitive operations without a clear user request.

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/auto_upgrade.py (reported line 429)May include surrounding context.

python
def run_external(command: list[str]) -> subprocess.CompletedProcess[str]:
    try:
        return subprocess.run(command, check=False, capture_output=True, text=True, timeout=120)
    except FileNotFoundError as exc:
        return subprocess.CompletedProcess(command, 127, "", str(exc))
    except subprocess.TimeoutExpired as exc:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This Python file contains natural-language documentation and generated report/output text exclusively in Chinese, and the program emits Chinese report content by default. Because the skill does not offer a language or locale choice, it imposes a specific language on users, which matches the stated natural-language locale policy violation criteria.

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/update_all.py (reported line 14)May include surrounding context.

python
def run(command: list[str], cwd: Path) -> None:
    print("+ " + " ".join(command), flush=True)
    subprocess.run(command, cwd=str(cwd), check=True)


def run_auto_upgrade_plan(args: argparse.Namespace, root: Path, data_dir: Path, report_dir: Path) -> None:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

In baseline mode, the script moves active snapshot files into an archive directory via archive_active_snapshots, which alters the on-disk state of prior snapshots. Although the CLI flag name hints at a reset, the code lacks any confirmation prompt or explicit warning print/log stating that existing snapshot files will be moved before the operation occurs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The guidance says to 'add ... bilingual search terms' as part of maintenance work, which imposes a language-related requirement without any user opt-in or explicit justification. This can violate locale/language policy because it assumes a specific multilingual presentation should be applied to all skills.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This code performs filesystem writes for raw JSON and processed CSV outputs, but there is no confirmation prompt or explicit warning before creating directories and writing files. Because the script collects and persists remotely fetched data, a brief disclosure would improve user awareness of local data modification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.