Back to skill

Security audit

mifu-chem-mindmap

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent chemistry mind-map generator, but its HTML renderer can carry unsafe content from input data and its validation claims are stronger than the code supports.

Install only if you will use trusted JSON inputs and manually review generated HTML before sharing it with teachers or students. Do not rely on the script's all-green validation as a complete safety or correctness guarantee; equations with skipped parsing and rendered output counts need human review, and the renderer should be fixed to escape HTML/SVG content before handling untrusted data.

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
scripts/mindmap_tools.py:219
Finding
Unescaped JSON Content Allows Stored HTML and SVG Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mindmap_tools.py:219, 223-238, 248-251, 260, 295-302` **Vulnerability Type**: Stored HTML/SVG injection **Risk Level**: High ### Vulnerable Code ```python def render_valence_svg(axis): ... for note in axis.get('special', []): svg.append(f'<text x="{note.get("x", w//2)}" y="{note.get("y", 112)}" font-size="11" text-anchor="middle" fill="#b91c1c">★{note.get("text","")}</text>') svg.append('</svg>') return '\n'.join(svg) def render_node(nd): parts = ['<div class="node">'] if nd.get('text'): parts.append(f'<span class="node-text">{nd["text"]}</span>') if nd.get('eq'): parts.append(f'<div class="eq">{nd["eq"]}</div>') extra = nd.get('extra') if extra: parts.append(f'<div class="extra">{extra}</div>') if nd.get('tag'): for t in nd['tag'].split('|'): cls = {'常考': 'tag-red', '易错': 'tag-yellow', '可推': 'tag-green', '必须记': 'tag-gray'}.get(t.strip(), 'tag-gray') parts.append(f'<span class="tag {cls}">{t.strip()}</span>') parts.append('</div>') return '\n'.join(parts) ``` Additional unescaped insertion points in `render_html` include: ```python secs.append(f'<div class="section"><div class="sec-title">▸ {sec.get("title","")}</div>{nodes}</div>') branch_html.append( f'<div class="branch-card" style="border-left-color:{color}">' f'<div class="branch-head" style="color:{color}"><span class="branch-num" style="background:{color}">{b.get("id", idx+1)}</span>{b.get("title","")}</div>' + ''.join(secs) + '</div>') <title>{meta.get('module','')}|三层思维导图</title> <h1>{meta.get('module','')}|三层思维导图</h1> <div class="sub">主题式包装:{meta.get('theme','')} | {meta.get('grade_region','')} · {meta.get('textbook','')} | 配套教案:mifu-chemistry-lesson-prep</div> <div class="footer">{stats_line} | validate: {data.get('_validate_status','未运行')} | 生成日期:{today} | 米赋教育教研中心 · mifu-chem-mindmap v{meta.get('skill_ver ...[truncated 2413 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Escape every untrusted value before inserting it into HTML text: ```python from html import escape def html_text(value): return escape(str(value), quote=True) ``` 2. Apply escaping consistently to: - Node text, equations, extra content, and tags - Section and branch titles - Module, theme, region, textbook, and version metadata - SVG note and species text - Footer values 3. Do not rely on text escaping for numeric SVG attributes. Validate and normalize them: ```python def safe_number(value, default): if isinstance(value, (int, float)): return value return default ``` 4. Validate the complete input against a strict schema before rendering. Reject unknown types, unexpected nested values, and fields exceeding reasonable size limits. 5. Prefer a template engine with autoescaping enabled rather than constructing markup through f-strings. 6. Add a restrictive Content Security Policy to generated files, such as one that disallows scripts, plugins, framing, and remote resources. CSP should be defense in depth rather than a substitute for escaping. 7. Add regression tests covering payloads in every rendered field, including: - `<script>` elements - Event-handler attributes - SVG element termination - Quotes in SVG coordinates and IDs - Remote image or frame elements ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mindmap_tools.py:150
Finding
Validation Logic Can Falsely Mark Unverified or Inconsistent Output as Passing<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mindmap_tools.py:150-158, 326-358` **Vulnerability Type**: Fail-open validation and ineffective consistency checks **Risk Level**: Medium ### Vulnerable Code The V1 validator records unparseable equations as skipped but does not count them as errors: ```python def v1_validate(data): bank = data.get('equations_bank', []) errors, skipped, ok = [], [], 0 for eq in bank: r = check_equation(eq) if r == 'SKIP': skipped.append(eq) elif r: errors.append((eq, r)) else: ok += 1 return bank, ok, skipped, errors ``` The main workflow considers V1 successful whenever the explicit error list is empty, regardless of skipped equations: ```python if skipped: print(' ⚠️ 人工核对(含变量): ' + ' || '.join(skipped)) for eq, msg in errors: print(f' ❌ {eq} -> {msg}') ... v1_pass = len(errors) == 0 v2_pass = coverage >= 85 ... status = '✅ 全绿' if (v1_pass and v2_pass) else '❌ 未通过' ``` The V3 equation-count condition is always true because a string count cannot be negative: ```python n_nodes = sum(len(sec.get('nodes', []) ) for b in data.get('branches', []) for sec in b.get('sections', [])) n_eq_html = html.count('class="eq"') residue = [p for p in ['None', '{{', '}}'] if p in html] print('-' * 60) print(f'V3 渲染检查: HTML已生成 {out} ({len(html)}字节)') print(f' 方程式块渲染数: {n_eq_html} | 节点数(数据): {n_nodes} | 残留占位符: {residue if residue else "无"}') v3_pass = (not residue) and n_eq_html >= 0 print(f'交付门槛: V1={"✅" if v1_pass else "❌"} V2={"✅" if v2_pass else "❌"} V3={"✅" if v3_pass else "❌"}') ``` The `all` command also writes the output before enforcing the final validation result: ```python if cmd == 'all': data['_validate_status'] = status out = sys.argv[3] html = render_html(data, count_stats(data)) with open(out, 'w', encoding='utf-8') as f: f.write(html) ``` ### Technical Analysis The validation workflow fail ...[truncated 2416 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat skipped equations as validation failures unless an explicit, auditable manual approval is supplied: ```python v1_pass = not errors and not skipped ``` 2. Distinguish the states `PASS`, `FAIL`, and `MANUAL REVIEW REQUIRED`. Never label content “all green” while unverified equations remain. 3. Perform exact V3 comparisons: ```python expected_nodes = sum( len(sec.get('nodes', [])) for branch in data.get('branches', []) for sec in branch.get('sections', []) ) expected_equations = sum( 1 for branch in data.get('branches', []) for sec in branch.get('sections', []) for node in sec.get('nodes', []) if node.get('eq') ) expected_branches = len(data.get('branches', [])) rendered_nodes = html.count('class="node"') rendered_equations = html.count('class="eq"') rendered_branches = html.count('class="branch-card"') v3_pass = ( not residue and rendered_nodes == expected_nodes and rendered_equations == expected_equations and rendered_branches == expected_branches ) ``` 4. Verify that every equation embedded in a node has an exact corresponding entry in `equations_bank`, and optionally reject unused bank entries. 5. Gate output creation on successful validation: ```python if not (v1_pass and v2_pass): print("Validation failed; output was not generated.") sys.exit(2) ``` 6. If generating failed output is needed for debugging, require an explicit option such as `--allow-invalid-output`, clearly mark the file as invalid, and avoid using a delivery filename. 7. Add automated tests for: - One or more skipped equations - Zero equations - Missing rendered nodes - Missing rendered branches - Source/render count mismatches - Failed V1 or V2 under the `all` command ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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 (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill instructs the agent to create and render output files such as JSON and HTML and explicitly references commands that write artifacts, but it does not declare any tool scope or permissions boundaries. That mismatch can cause an execution environment to grant broader file-write capability than users expect, increasing the risk of unintended overwrites or writes outside the intended workspace.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This markdown file contains instructional content exclusively in Chinese and does not indicate that users may choose another language or locale. Under the policy rule for language/locale constraints, forcing a single language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The entire skill guidance is written only in Chinese and provides no indication that users may choose another language or locale. Under the policy, forcing a specific language without opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The module usage text states that `validate <data.json>` performs `V1方程式守恒+V2完整度+V3渲染一致性`. In the implementation, the `validate` path only runs `v1_validate` and `v2_validate`; V3 checks are executed only inside the `all` branch after HTML rendering.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This Python file embeds natural-language output that forces the generated HTML to use `lang="zh-CN"` and presents the interface text entirely in Chinese. Under the policy for natural-language violations, a fixed language/locale without user opt-in should be flagged unless the locale restriction is explicitly justified.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The markdown specifies a fixed Chinese font fallback chain ("PingFang SC / Hiragino Sans GB") and the skill content is written as mandatory Chinese-language output guidance, with no opt-in or alternative locale path. Under the policy rule, forcing a specific language/locale presentation without user choice can be a natural-language policy concern unless clearly justified as region-specific.

Static analysis

No suspicious patterns detected.