Back to skill

Security audit

capsule-bookshelf-skill

Security checks for vulnerabilities and agentic risk

Overview

This looks like a legitimate Chinese book-excerpt HTML generator, but it needs Review because generated pages can run injected HTML/JavaScript and the active generator does not enforce the path containment it claims.

Install only if you are comfortable with a local skill that runs a Python generator, writes HTML output, and updates a persistent bookshelf registry. Review generated HTML before opening or sharing it, avoid feeding it untrusted JSON or copied web text, and do not manually add registry paths outside the skill's own generated files until path containment and HTML escaping are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
generate-book-article.py:104
Finding

Stored HTML and JavaScript Injection in Generated Articles and Bookshelf Pages

Content
View full analysis
str: """为单张卡片生成 HTML。""" number = card.get('number', '') book_title = card.get('book_title', '') book_info = card.get('book_info', '') quotes = card.get('quotes', []) # 构建金句列表 quote_parts = [] for j, q in enumerate(quotes): idx = q.get('index', f'{j + 1:02d}') text = q.get('text', '') quote_parts.append( QUOTE_ITEM_TEMPLATE.replace('{INDEX}', idx).replace('{TEXT}', text) ) if j < len(quotes) - 1: quote_parts.append(QUOTE_SEPARATOR) quotes_html = '\n'.join(quote_parts) if quote_parts else '' return (CARD_TEMPLATE .replace('{NUMBER}', number) .replace('{BOOK_TITLE}', book_title) .replace('{BOOK_INFO}', book_info) .replace('{QUOTES}', quotes_html)) ``` Additional direct substitutions in `generate-book-article.py:190-248` include: ```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 += '
' + 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 '') if gq_0: html = html.replace('{{GOLD_QUOTE_1}}', gq_0.get('text', '')) html = html.replace('{{GOLD_QUOTE_1_SOUR ...[truncated 4011 chars]
Remediation
View remediation
` must be supported, sanitize input with a strict allowlist rather than exempting the entire value from escaping. 5. Validate the JSON schema and reject unexpected objects, arrays, markup-bearing values, and excessively large strings. 6. Remove inline event handlers where possible and attach events from static JavaScript. 7. Add a restrictive Content Security Policy that blocks inline scripts and event handlers, for example through an appropriate `` policy for local HTML. 8. Add regression tests using payloads in every rendered field and verify that payloads appear as text rather than executable markup. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
generate-book-article.py:387
Finding

Missing Path Containment in the Active Inline Bookshelf Generator

Content
View full analysis
2 else str( DEFAULT_OUTPUT_DIR / (Path(json_path).stem + '-article.html') ) try: data = load_json(json_path) html_path = generate(data, output_path) # 自动注册到书架并刷新 gold_quotes = data.get("gold_quotes", []) cover_line = gold_quotes[0]["text"].replace("
", " ") if gold_quotes else "" book_title = data.get("title", Path(json_path).stem) author = data.get("author", book_title) rel_path = Path(os.path.relpath(html_path, SCRIPT_DIR)).as_posix() _register_capsule(book_title, author, rel_path, cover_line) _generate_bookshelf() ``` The generated output is written without containment validation in `generate-book-article.py:282-287`: ```python output = Path(output_path) output.parent.mkdir(parents=True, exist_ok=True) with open(output, 'w', encoding='utf-8') as f: f.write(html) ``` ### Technical Analysis The article generator contains an inline bookshelf implementation that is the implementation invoked by its CLI entry point. It resolves registry paths by joining `SCRIPT_DIR` with the registry-controlled `html_path`, but it does not canonicalize the resulting path or verify that it remains inside an authorized directory. A registry value such as: ```text ../../sensitive-file ``` can therefore resolve outside the project directory. If the target exists and is readable as UTF-8 text, i ...[truncated 2231 chars]
Remediation
View remediation
Path: base = base_dir.resolve(strict=True) path = (base / candidate).resolve(strict=False) try: path.relative_to(base) except ValueError: raise ValueError(f"Path escapes authorized directory: {candidate}") return path ``` 3. Reject absolute paths and traversal components before registration. 4. Define separate authorized roots for: - Temporary JSON input. - Final article output. - Project registry and bookshelf files. 5. Resolve symlinks and verify containment after resolution to prevent symlink-based escapes. 6. Validate existing registry entries before reading them, not only when adding new entries. 7. Refuse non-regular files and consider an `.html` extension allowlist for capsule files. 8. Do not automatically create arbitrary parent directories outside the authorized output root. 9. Write generated files atomically using a temporary file within the destination directory followed by `os.replace()`. 10. Add tests for `../` traversal, absolute paths, mixed separators, symlink escapes, and output paths outside the configured root. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (14)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill explicitly instructs use of write_file and shell_executor, but the manifest does not declare any tool scope or allowed-tools restrictions. This creates an authorization gap: a host may expose broader file or execution capabilities than intended, increasing the blast radius if the skill is misused or its inputs become adversarial.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill is entirely specified in Chinese and directs a fixed Chinese-language presentation style without offering the user any language or locale choice. Under the policy, forcing a specific language is a violation unless the locale constraint is explicitly justified or user opt-in is provided.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger list includes relatively broad phrases like “做书摘” and “帮我做一张XX的书摘,” which could match normal conversation and invoke the skill unintentionally. Unintended activation matters here because the skill performs autonomous content collection and file writes without additional confirmation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The HTML document declares lang="zh-CN", and the visible UI text throughout the template is also fixed in Chinese. This imposes a specific language/locale without offering opt-in, selection, or any stated region-specific requirement, matching the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger list contains generic phrases such as '做书摘', '浓缩一本书', and 'book-capsule' that can overlap with ordinary reading, summarization, or note-taking requests. This can cause the skill to activate without clear user intent, unexpectedly taking over benign conversations and routing user content into the skill’s workflow, which is a prompt-routing and consent issue even if the skill’s purpose is non-malicious.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The markdown explicitly encourages users to save generated reading capsules to '手机 / 电脑 / 云盘', which includes third-party cloud storage. Because the content is derived from personal reading archives and user-supplied data, the documentation should warn that uploading generated files to cloud services may expose personal content or metadata.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This file contains natural-language guidance, comments, and field descriptions only in Chinese, which effectively imposes a specific language on users of the skill/template. The policy allows language constraints when users are given a choice or when the locale restriction is clearly documented and justified, neither of which appears here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This JSON content is entirely authored in Chinese and provides no indication that language selection is optional or that the file is intended only for a Chinese-language or region-specific experience. Under the policy rule for natural-language violations, a fixed locale without opt-in or clear justification can be a compliance issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This JSON content presents the skill data exclusively in Chinese across titles, descriptions, and quotes, with no indication that the user can opt into another language or locale. Under the stated policy, forcing a specific language without user choice is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The document declares lang="zh-CN", which sets a specific language/locale for the skill experience. Under the policy criteria, forcing a specific locale without user opt-in or a documented region-specific justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The user-facing title and subtitle are entirely in Chinese, which indicates a fixed language/locale choice in the skill metadata. The file does not provide any indication that users can choose another language or that the Chinese-only presentation is required for a documented region-specific purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The generated document always uses lang="zh-CN", which imposes a specific language/locale regardless of user input. The file does not indicate that this is an optional or region-specific constraint, nor does it provide a way to select another locale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This code writes generated HTML output and updates the capsule registry on disk, but the only user-facing disclosure appears after the writes succeed. There is no prior warning in comments/docstrings or confirmation that running the script will modify multiple local files, including the registry and bookshelf artifacts.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

Natural-language policy review applies to all file types. The manifest presents the description and nearly all trigger phrases exclusively in Chinese, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-only audience for a documented reason.

Content

No source excerpt is available for this finding.