T09 · Insecure Skill Coding Practices
- Location
renderer.js:50- Finding
Untrusted candidate data is rendered without Markdown escaping
- Content
View full analysis
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
View remediation
