Back to skill

Security audit

book-capsule-skill

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local book-excerpt HTML generator, but it needs review because untrusted content can become executable browser code in the generated article.

Install only if you are comfortable with a skill that writes local files and runs its bundled Python generator automatically. Use trusted JSON/content sources, review generated HTML before opening or publishing it, and avoid feeding it web-scraped or user-supplied text unless the generator is updated to escape or sanitize HTML.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
generate-book-article.py:121
Finding
Unescaped JSON Content Permits Stored HTML and JavaScript Injection<![CDATA[ ## Vulnerability Details **File Location**: `generate-book-article.py`, lines 121–122; additional affected sinks at lines 133, 207–225, and 296 **Vulnerability Type**: Stored HTML/JavaScript injection **Risk Level**: High ### Vulnerable Code ```python quote_parts.append( QUOTE_ITEM_TEMPLATE.replace('{INDEX}', idx).replace('{TEXT}', text) ) ``` Additional vulnerable interpolation points include: ```python def build_gold_quote_html(gq: dict) -> str: """为一条金句生成独立 HTML 块。""" text = gq.get('text', '') source = gq.get('source', '') if source: return GOLD_QUOTE_BLOCK_TEMPLATE.replace('{TEXT}', text).replace('{SOURCE}', source) else: return GOLD_QUOTE_BLOCK_NO_SOURCE_TEMPLATE.replace('{TEXT}', text) ``` ```python title = data.get('title', '') if data.get('title_line2'): line2 = data['title_line2'] line2 = (line2 .replace('{count}', str(total_cards)) .replace('{all_quotes}', str(total_all_quotes)) .replace('{quotes}', str(total_quotes))) title += '<br>' + line2 html = html.replace('{{TITLE}}', title) html = html.replace('{{SUBTITLE}}', data.get('subtitle', '')) intro = data.get('intro_paragraphs', []) html = html.replace('{{INTRO_PARAGRAPH_1}}', intro[0] if len(intro) > 0 else '') html = html.replace('{{INTRO_PARAGRAPH_2}}', intro[1] if len(intro) > 1 else '') ``` ```python html = f'<!DOCTYPE html>\n<html lang="zh-CN">\n<head>\n<meta charset="utf-8">\n<meta name="viewport" content="width=600">\n<title>{data.get("title", "")}</title>\n</head>\n<body style="margin:0;padding:0;">\n{html}\n</body>\n</html>' ``` ### Technical Analysis The generator treats JSON values as trusted HTML and inserts them directly into HTML templates through string replacement and f-string interpolation. It does not apply HTML escaping, contextual output encoding, or markup sanitization. The affected data includes card numbers, titles, descriptions, quote text, quote sources, article tit ...[truncated 2766 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply contextual HTML escaping to every value originating from JSON: ```python from html import escape def escape_text(value) -> str: return escape(str(value), quote=True) ``` 2. Escape values before inserting them into text, attribute, or `<title>` contexts: ```python safe_text = escape_text(q.get('text', '')) safe_index = escape_text(q.get('index', f'{j + 1:02d}')) quote_parts.append( QUOTE_ITEM_TEMPLATE .replace('{INDEX}', safe_index) .replace('{TEXT}', safe_text) ) ``` 3. Do not preserve arbitrary HTML merely to support line breaks. Instead, escape the entire value and then convert only an explicitly supported representation: ```python def escape_with_breaks(value) -> str: safe = escape(str(value), quote=True) return safe.replace('\r\n', '\n').replace('\r', '\n').replace('\n', '<br>') ``` If backward compatibility with literal `<br>` is required, normalize and allow only exact `<br>`, `<br/>`, or `<br />` tokens after escaping. Do not use a broad tag-removal regular expression as a sanitizer. 4. Use a template engine with automatic escaping enabled rather than constructing HTML through unrestricted `str.replace()` operations. Treat any deliberately safe HTML fragment as a separate, explicitly typed value. 5. Add strict schema validation: - Require expected types for all fields. - Reject objects or arrays where strings are expected. - Validate `after_card` as a bounded non-negative integer. - Impose reasonable length and collection-size limits. - Reject unsupported fields or markup where practical. 6. Add regression tests covering payloads in every interpolated field, including: ```html </title><script>alert(1)</script> <img src=x onerror=alert(1)> <a href="javascript:alert(1)">link</a> ``` Tests should confirm that these values appear only as inert text in the generated document while supported line breaks continue to render correctly. 7. Consider applying a res ...[truncated 157 chars]
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (12)

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill description is entirely written in Chinese and presents the workflow and usage as Chinese-only, with no indication that users may choose another language or that the skill is intentionally restricted to a Chinese-language audience for a documented reason. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill instructs the agent to write a JSON file locally and invoke a shell command, but it does not declare any explicit tool scope or permission boundaries. This creates an over-privileged execution pattern where file system and command execution capabilities may be available without clear limitation or user awareness, increasing the chance of unintended local writes or misuse if the workflow is adapted or the inputs become unsafe.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The skill description and instructions are entirely in Chinese and define Chinese-language output conventions, but there is no indication that the user can choose another language or that the locale restriction is required for a justified regional purpose. This can violate language/locale policy when a skill implicitly forces a specific language without opt-in.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger phrases are broad natural-language requests like '做书摘' and '浓缩一本书', which can match ordinary user intent and cause the skill to activate unexpectedly. Unintended activation is risky here because the skill performs side effects, including local file creation and shell-based HTML generation, without an explicit confirmation step.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill description and workflow do not warn the user that local files will be written and a shell command will be executed. This reduces informed consent and can lead users to trigger filesystem and process side effects unknowingly, which is especially problematic in environments where shell execution is sensitive.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
This JSON content presents all user-facing titles, descriptions, and quotes exclusively in Chinese, but does not indicate that the skill is intended only for Chinese-speaking users or that language selection is optional. Under the policy, forcing a specific language without user opt-in can be a natural-language locale violation.

Vague Triggers

Medium
Confidence
96% confidence
Finding
Several trigger phrases such as '做书摘' or '浓缩一本书' are generic enough to match normal reading, summarization, or note-taking requests that may not explicitly intend to invoke this skill. This can cause unintended activation, leading the agent to access local files or publish content when the user only asked for general help, which is a real safety and consent issue even without malicious intent.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The natural-language instructions and labels in the file force a specific language/locale experience for anyone using the template. The policy allows this only when the skill offers user choice or clearly documents a justified region-specific constraint, which is not present here.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The generated document hard-codes lang="zh-CN", which imposes a specific language/locale on all output. The file does not offer a user option to select another locale or explain that the tool is intentionally limited to a China-specific publishing context.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
This HTML template presents all instructions and end-user visible content exclusively in Chinese, and there is no indication that the user can select another language or that the locale restriction is intentional. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
Natural-language text in the manifest presents the skill solely in one language without stating that it is China-specific or offering multilingual use. That can create a language policy concern if the broader environment expects neutral language support or user opt-in for locale-specific behavior.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
This markdown file presents all user-facing instructions in Chinese starting from the title, with no indication that users may choose another language or that the locale restriction is intentional. That can violate a language/locale policy when a skill forces a specific language without user opt-in.

Static analysis

No suspicious patterns detected.