Back to skill

Security audit

Math Viz

Security checks for vulnerabilities and agentic risk

Overview

This math visualization skill is mostly coherent, but its required local verification script has unsafe file-handling bugs that could run unintended commands or tamper with files.

Review this skill before installing. Its visualization behavior is understandable, but only run the verifier on trusted filenames and generated files, avoid filenames containing quotes or shell/Python metacharacters, and prefer a fixed verifier that passes paths as arguments and uses private temporary files.

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/verify_output.sh:84
Finding

Arbitrary Python Code Execution Through Unsafe File Path Interpolation

Content
View full analysis
]*)>(.*?)', html, re.DOTALL)) found = False for m in reversed(scripts): attrs = m.group(1).strip() if 'src=' not in attrs: code = m.group(2).strip() if len(code) > 50: with open('/tmp/_mathviz_verify.js', 'w') as f: f.write(code) found = True break if not found: print('NOT_FOUND') " 2>/dev/null > /tmp/_mathviz_extract_result ``` Equivalent vulnerable interpolation is used in the other Python blocks: ```bash html = open('$HTML', 'r', encoding='utf-8').read() ``` and: ```bash html = open('$HTML').read() ``` ### Technical Analysis The verifier accepts the HTML path from its first positional argument: ```bash HTML="$1" ``` It then embeds that value directly into Python source code passed through `python3 -c`. Although the shell variable is expanded inside a double-quoted shell string, the resulting value is placed inside a single-quoted Python string literal without Python escaping. Consequently, a path containing a single quote can terminate the Python string. Additional Python statements in the path are then interpreted as executable source code. Shell quoting of `"$1"` at assignment time does not prevent this second-order injection because the vulnerable interpretation occurs when the expanded value becomes part of Python source. This pattern occurs in four separate Python invocations, increasing the available opportunities for exploitation. ### Attack Path 1. An attacker gains the ability to control or influence the output HTML filename ...[truncated 1481 chars]
Remediation
View remediation
]*)>(.*?)", html, re.DOTALL) ) PY ``` Apply this correction to every Python invocation at lines 84, 122, 182, and 217. Additional hardening should include: 1. Reject missing arguments before using `$1`: ```bash if [ "$#" -ne 1 ]; then printf 'Usage: %s \n' "$0" >&2 exit 2 fi ``` 2. Resolve and validate the path before processing it. 3. If output must remain in a workspace, verify that the resolved path remains beneath the approved workspace directory. 4. Use `--` before path operands in external commands where supported. 5. Add regression tests using filenames containing single quotes, newlines, spaces, backslashes, and Python metacharacters. 6. Avoid suppressing all Python errors with `2>/dev/null`, since doing so can conceal attempted exploitation and validation failures. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/verify_output.sh:92
Finding

Symlink and Race Attacks Through Predictable Shared Temporary Files

Content
View full analysis
50: with open('/tmp/_mathviz_verify.js', 'w') as f: f.write(code) found = True break if not found: print('NOT_FOUND') " 2>/dev/null > /tmp/_mathviz_extract_result if grep -q 'NOT_FOUND' /tmp/_mathviz_extract_result 2>/dev/null; then check "JS 语法检查" "fail (未找到内联脚本)" else if "$NODE" --check /tmp/_mathviz_verify.js 2>/dev/null; then check "JS 语法检查" "pass" else echo " --- 语法错误详情 ---" "$NODE" --check /tmp/_mathviz_verify.js 2>&1 ``` Other predictable files include: ```bash " 2>/dev/null > /tmp/_mathviz_bracket_result BR=$(cat /tmp/_mathviz_bracket_result) ``` ```bash " 2>/dev/null > /tmp/_mathviz_angle_count ANGLE_COUNT=$(cat /tmp/_mathviz_angle_count 2>/dev/null || echo "0") ``` ```bash " 2>/dev/null > /tmp/_mathviz_create_result check "create()调用统计" "pass ($(cat /tmp/_mathviz_create_result))" ``` ### Technical Analysis The script uses fixed filenames directly beneath the globally shared `/tmp` directory. These files are created or truncated without: - Exclusive creation. - Verification that an existing path is a regular file. - Ownership checks. - Symlink protection. - A private per-process directory. - Cleanup after execution. Python's `open(path, 'w')` and shell output redirection follow symbolic links. A local attacker can therefore pre-create one of these predictable paths as a symbolic link to another file writable by the verifier user. When the verifier writes to the temporary path, it follows the link and truncates or overwrites the linked destination. There are also time-of-check/time-of-use windows between writing and subsequently reading or checking the same file ...[truncated 2638 chars]
Remediation
View remediation
&2 exit 1 } trap 'rm -rf -- "$VERIFY_TMP"' EXIT HUP INT TERM VERIFY_JS="$VERIFY_TMP/verify.js" EXTRACT_RESULT="$VERIFY_TMP/extract-result" BRACKET_RESULT="$VERIFY_TMP/bracket-result" ANGLE_COUNT="$VERIFY_TMP/angle-count" CREATE_RESULT="$VERIFY_TMP/create-result" ``` Pass these paths to Python as arguments or environment values rather than embedding them into Python source: ```bash python3 - "$HTML" "$VERIFY_JS" > "$EXTRACT_RESULT" <<'PY' import re import sys html_path = sys.argv[1] javascript_path = sys.argv[2] with open(html_path, "r", encoding="utf-8") as handle: html = handle.read() scripts = list(re.finditer(r"]*)>(.*?)", html, re.DOTALL)) found = False for match in reversed(scripts): attributes = match.group(1).strip() if "src=" not in attributes: code = match.group(2).strip() if len(code) > 50: with open(javascript_path, "x", encoding="utf-8") as handle: handle.write(code) found = True break if not found: print("NOT_FOUND") PY ``` Additional hardening should include: 1. Set a restrictive file-creation mask near the beginning of the script: ```bash umask 077 ``` 2. Quote every temporary path reference. 3. Use exclusive creation where files should not already exist. 4. Avoid reusing temporary files across verifier runs. 5. Keep generated files inside the private temporary directory. 6. Ensure cleanup occurs on normal exit and common termination signals. 7. Add parallel-execution tests to ensure multiple verifier instances cannot interfere with one another. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrases are broad everyday expressions such as '画图' and '演示一下', which can cause the skill to activate when the user did not clearly intend file generation, preview opening, or external resource loading. In this skill's context, accidental activation is more concerning because activation leads to creating HTML in the workspace and potentially opening a rendered page.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs writing HTML files to the workspace and opening them via preview while also requiring external CDN-loaded JavaScript, but it does not clearly disclose these side effects or obtain user consent. This matters because generated HTML is active content, and previewing it may execute third-party scripts in the user's environment, increasing privacy and supply-chain risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The requirement “中文界面:标题、标签、按钮、提示全部中文” imposes a fixed language/locale on all generated output. There is no indication that the user can opt into another language or that the Chinese-only constraint is justified as a region-specific requirement.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly requires running a local shell script via bash as part of normal operation, which expands its capabilities from HTML generation into host-level command execution. Even if the script is intended only for validation, mandating shell execution creates unnecessary attack surface because a modified script, path hijack, or unsafe future script changes could lead to unintended local code execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

All user-facing messages, headings, and usage guidance in the script are hardcoded in Chinese, with no indication that users may choose another language. This is a natural-language policy concern because it forces a specific language/locale regardless of user preference.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The output specification says 'Three.js用 cdn.jsdelivr.net', implying Three.js resources should come from jsDelivr. However, the provided Three.js skeleton loads three.min.js from cdnjs.cloudflare.com at L100, while only OrbitControls.js uses jsDelivr at L101, creating a direct documentation-to-code contradiction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The HTML example hard-codes the document language to "zh-CN", which indicates a fixed Chinese locale. The file does not mention any user opt-in, language selection, or justification for restricting output to this locale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script writes extracted JavaScript from the provided HTML into /tmp files and then invokes Node.js to syntax-check that content. Although the operations are visible in code comments, there is no user-facing warning, prompt, or runtime disclosure that the script will create temporary files and execute an external interpreter on extracted content.

Content

No source excerpt is available for this finding.