Back to skill

Security audit

Markdown to HTML Converter

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it says, but its HTML converter can produce unsafe browser/CMS output while the documentation presents it as safe for publishing.

Review before installing if you may convert untrusted Markdown or publish the result. This tool is acceptable for local trusted notes, but do not feed its output directly into a website, CMS, or database-rendered page without a real HTML sanitizer and URL validation.

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

Error
Location
scripts/md2html.js:101
Finding
Unsanitized Markdown Conversion Enables HTML Injection and Cross-Site Scripting<![CDATA[ ## Vulnerability Details **File Location**: `scripts/md2html.js`, lines 101-116; vulnerable output contexts are used at lines 51-89 **Vulnerability Type**: HTML injection and stored/reflected cross-site scripting (XSS) **Risk Level**: High ### Vulnerable Code ```javascript function inlineFormat(text) { // Images ![alt](url) — must come before links text = text.replace(/!\[(.+?)\]\((.+?)\)/g, '<img src="$2" alt="$1" style="max-width:100%;">'); // Bold **text** text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>'); // Italic *text* (Node v0.12+ compatible, no lookbehind needed) text = text.replace(/\*([^*\n]+?)\*/g, '<em>$1</em>'); // Inline code `text` text = text.replace(/`(.+?)`/g, '<code>$1</code>'); // Links [text](url) text = text.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>'); // Line breaks (double space at end of line) text = text.replace(/ $/gm, '<br>'); return text; } ``` Representative output sinks include: ```javascript result.push('<h1>' + inlineFormat(line.replace(/^#\s*/, '')) + '</h1>'); result.push('<blockquote><p>' + inlineFormat(line.replace(/^>\s*/, '')) + '</p></blockquote>'); result.push('<li>' + inlineFormat(line.replace(/^[\-\*]\s*/, '')) + '</li>'); result.push('<p>' + inlineFormat(line) + '</p>'); ``` ### Technical Analysis The converter inserts untrusted Markdown content into generated HTML without first applying HTML escaping. The `inlineFormat()` function also places attacker-controlled image URLs, link URLs, alternative text, and labels directly into HTML attribute or element contexts. The only escaping routine in the project is applied to fenced code-block contents. Ordinary paragraphs, headings, list items, blockquotes, inline code, links, and images remain unsafe. This creates multiple exploitation mechanisms: 1. **Direct HTML injection**: Raw HTML in an ordinary Markdown line is preserved inside the generated paragraph. 2. **Attribute inje ...[truncated 2704 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Escape text before formatting** - HTML-escape all untrusted Markdown text before placing it into element content. - Encode at least `&`, `<`, `>`, `"`, and `'` where appropriate. - Ensure inline-code content is escaped rather than merely wrapped in `<code>`. 2. **Apply context-aware attribute encoding** - Never interpolate captured regular-expression groups directly into quoted attributes. - Encode image alternative text, image sources, link destinations, and any future attribute values using an attribute-safe encoder. 3. **Validate link and image URL schemes** - Parse URLs and allow only explicitly required schemes, such as `https:`, `http:`, and optionally `mailto:`. - Reject `javascript:`, unsafe `data:`, `vbscript:`, file URLs, control characters, encoded scheme bypasses, and protocol-relative URLs unless specifically required. - Validation must occur after normalization and decoding. 4. **Sanitize the final HTML** - Use a maintained Markdown implementation with secure configuration. - Pass generated HTML through an allowlist-based HTML sanitizer before publishing it. - Allow only necessary elements and attributes, and remove event-handler attributes and dangerous URL protocols. - If raw HTML is unnecessary, disable raw HTML support entirely. 5. **Harden browser integration** - Apply an appropriately restrictive Content Security Policy as defense in depth. - Do not treat converted output as trusted solely because it was produced by this converter. - Preserve `rel="noopener"` and consider adding `noreferrer` where suitable, but do not treat these attributes as an XSS mitigation. 6. **Add security regression tests** - Test raw elements such as `<script>` and `<img onerror>`. - Test quote-breaking payloads in image alt text and URLs. - Test dangerous and obfuscated URL schemes. - Test HTML inside headings, lists, blockquotes, and inline-code spans. - Confirm ...[truncated 302 chars]
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Vague Triggers

Medium
Confidence
88% confidence
Finding
The skill advertises very broad trigger phrases and applicability, which can cause the agent to invoke this skill for generic content-processing requests outside a narrowly scoped Markdown-to-HTML workflow. Overbroad invocation increases the chance of inappropriate tool selection, accidental file handling, or unintended publication of generated HTML into downstream systems such as CMS pipelines.

Static analysis

No suspicious patterns detected.