Back to skill

Security audit

分院帽

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local personality-quiz skill, with a notable caution to use only trusted custom configuration files.

Install only if you are comfortable with a Chinese-language local quiz skill that can generate HTML files. Use the bundled data or custom configuration files you control; do not generate and share HTML from untrusted configs until the HTML/script escaping issue is fixed. The alt configuration is not fully de-IPed for commercial use.

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

Warning
Location
scripts/build_quiz_html.py:1051
Finding
HTML and JavaScript Injection Through Unescaped Custom Configuration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/build_quiz_html.py`, lines 1051–1074 **Vulnerability Type**: Stored HTML/JavaScript injection in generated quiz files **Risk Level**: Medium ### Vulnerable Code ```python def render_html(houses_data, questions_data, papers_data, glossary_data, config_label="canon"): payload, wide, zero = build_quiz_payload(houses_data, questions_data, papers_data, glossary_data, config_label) title = houses_data["card"]["title"] page_title = "%s · %s" % (title, config_label) if config_label not in ("canon", "main") else title js = (JS_CORE .replace("__QUIZ_JSON__", json.dumps(payload, ensure_ascii=False, indent=None, separators=(",", ":"))) .replace("__WIDE_CHARS__", json.dumps(wide, ensure_ascii=False)) .replace("__ZERO_WIDTH_CHARS__", json.dumps(zero, ensure_ascii=False))) html = (HTML_TEMPLATE .replace("__LANG__", UI_LABELS["lang"]) .replace("__PAGE_TITLE__", page_title) .replace("__UI_START__", UI_LABELS["start"]) .replace("__UI_PREV__", UI_LABELS["prev"]) .replace("__UI_NEXT__", UI_LABELS["next"]) .replace("__UI_DICT__", UI_LABELS["dict_button_alt"] if config_label == "alt" else UI_LABELS["dict_button"]) .replace("__UI_ANNOT_ON__", UI_LABELS["annot_on"]) .replace("__UI_POP_CLOSE__", UI_LABELS["pop_close"]) .replace("__UI_DICT_CLOSE__", UI_LABELS["dict_close"]) .replace("__PICKED__", "·" + UI_LABELS["picked"]) .replace("__JS_CORE__", js)) return html ``` The generated JavaScript is placed inside this inline script context: ```html <script> __JS_CORE__ ... </script> ``` ### Technical Analysis The HTML generator supports custom configuration files through the documented `--config`, `--houses`, `--questions-file`, and `--glossary` options. Values loaded from those files are collect ...[truncated 3289 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Apply script-context-safe JSON serialization.** Escape characters that can affect HTML parsing after calling `json.dumps()`: ```python def safe_script_json(value): return ( json.dumps(value, ensure_ascii=False, separators=(",", ":")) .replace("&", "\\u0026") .replace("<", "\\u003c") .replace(">", "\\u003e") .replace("\u2028", "\\u2028") .replace("\u2029", "\\u2029") ) ``` Use this function for `payload`, `wide`, and `zero` before inserting them into an inline script. 2. **HTML-escape every value inserted into markup contexts.** In particular: ```python import html safe_page_title = html.escape(page_title, quote=True) html_output = HTML_TEMPLATE.replace("__PAGE_TITLE__", safe_page_title) ``` Apply equivalent escaping to every template substitution according to its destination context. 3. **Prefer a non-executable data container.** Place configuration data in a dedicated element: ```html <script id="quiz-data" type="application/json">...</script> ``` The JSON must still escape `<`, `>`, and `&`. Parse it with: ```javascript const QUIZ = JSON.parse(document.getElementById('quiz-data').textContent); ``` 4. **Treat custom configuration files as untrusted input.** Validate all string fields and reject control sequences or unexpected markup where HTML is not intended. 5. **Add regression tests.** Generate pages using values containing: - `</script>` - `<script>alert(1)</script>` - `<`, `>`, `&`, single quotes, and double quotes - U+2028 and U+2029 - Closing `</title>` and `</h1>` sequences Tests should assert that these values remain inert text and that no additional script or markup elements are created. 6. **Consider a restrictive Content Security Policy.** A CSP can provide defense in depth, although it should not replace contextual output encoding. For a self-contai ...[truncated 129 chars]
Vulnerability Patterns
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
声明描述的是一个直接面向终端用户的“分院帽人格测试”技能,重点在运行期交互体验(触发语、答题页、文本问答闭环、提交判定)。但给出的代码块明确写明是“构建期工具,运行期用不到”,其职责仅是依据题库生成随机试卷数据并做一致性校验。虽然“随机抽卷”这一点与声明中的一部分概念相关,但这里只是离线预生成试卷,不是用户答题流程本身。代码没有任何页面生成、会话处理、用户输入采集、答案串回传、结果计算展示等核心能力,因此其主要用途与声明存在实质性偏差。

Ae1

High
Category
analysis-evasion
Content
- `data/questions.json` 是**题库**(33 道岔路),`data/papers.json` 是**试卷库**(33 张卷)。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill explicitly instructs the agent to execute shell commands, read local files, and generate/write HTML, but it does not declare any tool scope or permission boundaries. In an agent environment, this can lead to over-privileged execution, unexpected file access, or command execution beyond what is necessary for a personality-test skill.

Natural-Language Policy Violations

Medium
Confidence
83% confidence
Finding
Throughout the skill, all user-facing triggers, prompts, outputs, and examples are specified only in Chinese, and the instructions require the agent to relay script output verbatim. There is no indication that the user can opt into another language or that the Chinese-only constraint is a documented regional requirement.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger conditions include broad natural-language phrases and even generic complaints like '手打答案串太累/怕把题目搞混', which can cause unintended activation. In an agent setting, accidental invocation of a skill that can execute scripts and write files increases the chance of unnecessary local actions and user confusion.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
This JSON file contains user-facing metadata strings entirely in Chinese, including the title and explanatory text, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-speaking locale. Under the policy for natural-language violations, forcing a specific language without opt-in is a reportable issue.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This JSON manifest/content is entirely written as fixed Chinese user-facing strings, and there is no indication that the user can choose another language or that the skill is intentionally limited to Chinese-speaking use. Under the policy, forcing a specific language without opt-in is a natural-language locale violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This manifest-like JSON file contains all user-facing labels, prompts, and instructions exclusively in Chinese, indicating the skill is designed to interact in a fixed language. Under the policy rule, forcing a specific language without user opt-in or a documented region-specific justification is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The only descriptive note in this manifest-style JSON is written entirely in Chinese, which imposes a specific language on readers without offering any alternative or opt-in. That can violate language/locale policy for skills expected to be understandable across organizational users.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This JSON file contains user-facing descriptive text entirely in Chinese in the notes field, but there is no indication that the skill is intentionally region- or language-specific, nor any opt-in for language preference. Under the policy rules, forcing a specific language without user choice is a natural-language policy concern.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The scene, stem, and option text for the questionnaire are all written in Chinese, making the skill effectively Chinese-only. Because no language selection or explicit locale limitation is documented in this file, this is a policy-relevant language constraint.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This markdown file is entirely written in Chinese and presents all commands, expected outputs, and user-facing examples in Chinese without any indication that another language is supported or that the Chinese-only scope is intentional and region-specific. Under the policy rule, forcing a specific language without opt-in is a natural-language policy concern.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
L037 的验收项把 `--config alt --audit` 描述为“去 IP 化配置”,容易传达该模式整体已完成去 IP 化。可 L245-L248 明确说明 alt 仍共用 canon 题库,题干场景没有去 IP 化,只能算“换皮演示”,不应对外当去 IP 化版本发;这构成文档意图与实际状态的直接冲突。

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code embeds a fixed locale value (`zh-CN`) and all visible UI strings in Chinese, which constitutes a language/locale constraint expressed in natural language. The file does not indicate any user opt-in, language selection, or documented region-specific justification for forcing that locale.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
failed = 0
    for name, plan in plans:
        proc = subprocess.run([node, js_path, page_path, json.dumps(plan, ensure_ascii=False)],
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=tmpdir)
        if proc.returncode != 0:
            failed += 1
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
fh.write(js)

    def run(mode):
        proc = subprocess.run([node, js_path, mode], stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE, cwd=tmpdir)
        if proc.returncode != 0:
            raise RuntimeError("node 执行失败(%s):%s" % (mode, proc.stderr.decode("utf-8", "replace")[:800]))
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file’s user-facing instructions, prompts, and examples are written entirely in Chinese, and several parser error messages explicitly require Chinese responses from the user. Because the skill does not offer any language selection or opt-in mechanism, it effectively enforces a specific language/locale policy on all users.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/build_quiz_html.py:1221