Back to skill

Security audit

skill-kill

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent purpose, but its candidate renderer can let untrusted marketplace data alter displayed recommendations, links, or install commands.

Review this skill carefully before installing. Its goal is reasonable and it does not appear to auto-install or steal data, but hostile or malformed skill listings could make the output table misleading, including links or install commands. Prefer using it only when you will independently verify each source page and command before running anything.

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

Warning
Location
renderer.js:50
Finding
Untrusted candidate data is rendered without Markdown escaping<![CDATA[ ## Vulnerability Details **File Location**: `renderer.js`, lines 50–52 **Vulnerability Type**: Markdown content and link injection **Risk Level**: Medium ### Vulnerable Code ```js const header = `| ${headers.join(" | ")} |\n|${headers.map((_, index) => index === 2 ? "---:" : "---").join("|")}|`; const rows = items.map(item => `| ${item.name} | ${item.description} | ${item.matchScore} | ${item.trustLevel} | ${item.riskLevel} | [来源](${item.sourceUrl}) | ${item.permissions.join("、")} | ${item.recommendation} | \`${item.installCommand}\` |`); return [header, ...rows].join("\n"); ``` ### Technical Analysis The Markdown renderer directly interpolates externally sourced candidate fields into a Markdown table. Fields such as `name`, `description`, `sourceUrl`, `permissions`, and `installCommand` are not escaped or structurally validated before rendering. An attacker-controlled candidate can include Markdown metacharacters such as pipes, newlines, brackets, parentheses, or backticks. These characters can terminate table cells or inline-code spans, create additional rows, introduce deceptive links, or otherwise alter the apparent relationship between a candidate and its installation command. The normalization performed by `normalizeCandidate()` only supplies defaults and checks a small number of enumerations. It does not neutralize Markdown syntax or restrict `sourceUrl` to HTTP or HTTPS. ### Attack Path 1. An attacker publishes a Skill listing with crafted metadata in a marketplace or repository searched by the agent. 2. The candidate metadata contains Markdown control characters, such as a newline and pipe sequence in the description or backticks in the installation command. 3. The agent retrieves the listing and constructs a candidate object from that data. 4. `renderCandidates()` interpolates the fields directly into the Markdown table. 5. The rendered table is structurally altered, allowing the attacker to display deceptive candidate details, ...[truncated 965 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Implement context-aware Markdown escaping for every externally sourced field. - Replace embedded carriage returns and newlines with spaces before rendering table cells. - Escape table separators, brackets, parentheses, backticks, backslashes, and other Markdown control characters. - Render installation commands using a robust fenced-code strategy or escape backticks based on the longest backtick sequence in the value. - Parse `sourceUrl` with `new URL()` and allow only explicitly approved protocols, preferably `https:` and, where necessary, `http:`. - Reject malformed URLs and render them as plain text rather than links. - Apply reasonable length limits to externally sourced fields. - Add tests containing pipes, newlines, brackets, parentheses, backticks, embedded links, and malicious URL schemes. - Treat rendering sanitization as a mandatory enforcement layer rather than relying only on instructions in `SKILL.md`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
renderer.js:42
Finding
HTML source links accept unsafe URL schemes<![CDATA[ ## Vulnerability Details **File Location**: `renderer.js`, lines 42–48 **Vulnerability Type**: Unsafe URL scheme handling **Risk Level**: Medium ### Vulnerable Code ```js function renderCandidates(candidates, mode = "markdown") { const items = prepareCandidates(candidates); const headers = ["候选 Skill", "功能简介", "匹配度", "信任度", "安全风险", "来源", "关键权限/行为", "推荐结论", "安装命令"]; if (mode === "html") { const head = `<table><thead><tr>${headers.map(header => `<th>${escapeHtml(header)}</th>`).join("")}</tr></thead><tbody>`; const rows = items.map(item => `<tr><td>${escapeHtml(item.name)}</td><td>${escapeHtml(item.description)}</td><td>${item.matchScore}</td><td>${escapeHtml(item.trustLevel)}</td><td>${escapeHtml(item.riskLevel)}</td><td><a href="${escapeHtml(item.sourceUrl)}">${escapeHtml(item.sourceUrl)}</a></td><td>${item.permissions.map(escapeHtml).join("、")}</td><td>${escapeHtml(item.recommendation)}</td><td><code>${escapeHtml(item.installCommand)}</code></td></tr>`).join(""); return `${head}${rows}</tbody></table>`; } ``` ### Technical Analysis `escapeHtml()` prevents an attacker from terminating the `href` attribute and injecting arbitrary HTML markup. However, HTML escaping does not make a URL safe. The renderer places `item.sourceUrl` in an anchor without parsing the URL or validating its protocol. Consequently, values using schemes such as `javascript:`, `data:`, or unsafe custom protocols can be emitted as clickable links. Whether script execution is possible depends on the HTML host's sanitizer and browser policy, but the renderer itself provides no protection. Custom protocols may also invoke installed external handlers. This behavior conflicts with the Skill's documented prohibition against pseudo-links and custom protocols. ### Attack Path 1. An attacker creates a candidate listing whose source URL uses an unsafe scheme, such as a `javascript:`, `data:`, or custom-protocol URL. 2. The candidate is retrieved and passed to `norm ...[truncated 1089 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate URLs before generating an anchor: ```js function safeHttpUrl(value) { try { const url = new URL(String(value)); return url.protocol === "https:" || url.protocol === "http:" ? url.href : null; } catch { return null; } } ``` - Prefer an `https:`-only policy unless plain HTTP is required for a documented compatibility reason. - If validation fails, render escaped plain text such as `Unknown` instead of an anchor. - Apply the same URL validation to both HTML and Markdown rendering paths. - Do not rely on HTML escaping to enforce URL safety; escaping and protocol validation address different security boundaries. - Where generated HTML is embedded in a larger page, retain a defense-in-depth Content Security Policy and host-level HTML sanitizer. - Add regression tests for `javascript:`, `data:`, `file:`, protocol-relative URLs, custom schemes, malformed URLs, mixed-case schemes, and leading control characters. ]]>
Vulnerability Patterns
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Ae1

High
Category
analysis-evasion
Content
不要在 `SKILL.md` 中复制或改写这两个文件的实现;修改格式时优先更新外部文件,并同步检查本节约定。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The README's natural-language content, including the manifest description and all user-facing instructions, is entirely in Chinese with no indication that the skill can operate in other languages or that Chinese is required for a region-specific purpose. This creates a language/locale policy concern because it effectively imposes a specific language without user opt-in.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The manifest description is written as a direct operating description entirely in Chinese, and the file provides no indication that the skill can respond in another language or lets the user choose locale. Under the policy, a skill that forces a specific language without user opt-in is a natural-language policy violation.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The schema permits multiple unconstrained free-text fields such as description, sourceType, sourceUrl, repositoryUrl, version, lastUpdated, and especially installCommand. In a skill-selection context, these fields can carry prompt-injection content, misleading activation guidance, or unsafe installation instructions that downstream agents may trust or render without validation.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The enum values for `trustLevel`, `riskLevel`, and `recommendation` are hard-coded in Chinese, which imposes a specific language/locale in the schema itself. This is a natural-language policy concern because the file does not indicate user choice, localization support, or a documented region-specific justification.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This JavaScript file embeds Chinese strings for trust levels, recommendations, and later renders Chinese-only table headers and default values. Per the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified, which is not present in this file.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The renderer produces user-facing output entirely in Chinese, including headers such as '候选 Skill', '功能简介', and '安装命令', as well as link text and separators. Because the file does not provide a language choice or indicate that the skill is intentionally region-specific, this appears to violate the language/locale policy.

Static analysis

No suspicious patterns detected.