Back to skill

Security audit

HTML Markdown Hybrid

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent HTML and Markdown conversion skill, but it needs review because it can fetch arbitrary URLs and generate unsafe active HTML from untrusted input.

Install only if you trust the Markdown, HTML, and URLs you ask it to process. Avoid running URL conversion in environments that can reach private services or cloud metadata, and do not publish or open generated HTML from untrusted Markdown unless it has been sanitized. Review or update dependencies before using it for bulk or hostile input.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/html_to_markdown.mjs:221
Finding

Unrestricted URL Fetching Enables Server-Side Request Forgery

Content
View full analysis
controller.abort(), timeoutMs); try { const res = await fetch(url, { redirect: 'follow', signal: controller.signal }); if (!res.ok) throw new Error(`Fetch failed: ${res.status} ${res.statusText}`); return await res.text(); } finally { clearTimeout(timer); } } async function readInput(args) { if (args.file) return fs.readFile(args.file, 'utf8'); if (args.html) return args.html; if (args.url) return fetchWithTimeout(args.url, args.timeoutMs); throw new Error('No input'); } ``` The same unrestricted fetch function is used for URL-list batch processing: ```js for (const u of urls) { const out = path.join(args.outputDir, fileNameFromUrl(u)); try { const raw = await fetchWithTimeout(u, args.timeoutMs); const res = await convertOne(raw, args, u); await writeFileEnsure(out, res.markdown); ``` ### Technical Analysis The values supplied through `--url` and `--url-list` reach `fetch()` without validation of the URL scheme, destination hostname, resolved IP address, or network range. Although the command help presents an HTTPS URL, the implementation does not enforce HTTPS or restrict requests to public Internet addresses. The fetch operation also enables automatic redirects through `redirect: 'follow'`. Consequently, validating only the initial URL outside this function would not be sufficient: an apparently public endpoint could redirect the request to a loopback, private, link-local, or cloud metadata address. The response body is converted to Markdown and written to a caller-selected output file. Therefore, a user who can control the URL and subsequently read ...[truncated 1552 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/markdown_to_html.mjs:104
Finding

Raw Markdown HTML Is Preserved, Enabling Stored Cross-Site Scripting

Content
View full analysis
${CSS[opts.theme] || CSS.light}` : ''; return ` ${String(title).replace(/</g,'<')} ${css} ${body} `; } ``` ### Technical Analysis The Markdown renderer is initialized with `html: true`. This setting instructs `markdown-it` to preserve raw HTML supplied in the Markdown source. The resulting HTML body is then interpolated directly into the generated document without sanitization. For example, untrusted Markdown containing the following content can produce an executable script in the output: ```html ``` Other active content, including event-handler attributes, malicious forms, iframes, or dangerous embedded elements, may also survive. The title receives partial escaping, but this does not protect the document body. This is a stored injection vulnerability because the malicious markup is saved in the generated HTML and executes later when a user opens or hosts that file. ### Attack Path 1. An attacker creates or modifies Markdown that will be processed by the Node renderer. 2. The Markdown contains raw active HTML, such as a script element or an element with an event handler. 3. The converter initializes `markdown-it` w ...[truncated 1165 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pretty_markdown_to_html.py:76
Finding

Python Markdown Renderer Fails to Escape Text and Attribute Values

Content
View full analysis
', text) # Links text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'\1', text) # Bold+italic text = re.sub(r'\*\*\*(.+?)\*\*\*', r'\1', text) # Bold text = re.sub(r'\*\*(.+?)\*\*', r'\1', text) # Italic text = re.sub(r'\*(.+?)\*', r'\1', text) # Inline code text = re.sub(r'`([^`]+)`', r'\1', text) # Strikethrough text = re.sub(r'~~(.+?)~~', r'\1', text) return text ``` The unescaped result is used in multiple HTML contexts: ```python if m: close_para() close_list() level = len(m.group(1)) html_lines.append(f'{inline(m.group(2))}') continue ``` ```python if not in_paragraph: close_list() html_lines.append('

') in_paragraph = True html_lines.append(inline(stripped)) ``` The generated body is then embedded directly in the final document: ```python body = md_to_html(md_text) title = html_mod.escape(args.title) result = f""" {title} {css} {body} """ ``` ### Technical Analysis The converter escapes fenced code-block lines and the document title, but ordinary Markdown text is not HTML-escaped before being inserted into the output. Consequently, raw HTML in paragraphs, headings, list entries, or blockquotes can be interpreted as markup ...[truncated 2014 chars]

Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code does match one subset of the description: Markdown to nicer-looking standalone HTML pages. However, the declared purpose presents a broader dual-purpose skill combining Markdown→HTML with robust HTML→Markdown extraction and advanced cleanup/workflow features. The provided code chunk only implements the Markdown→HTML half, using a simple custom parser and embedded CSS themes. There is no evidence of HTML input processing, extraction from URLs/directories, metadata/report generation, cleanup profiles, or any Node-based pipeline. Because major declared capabilities are missing from the actual code chunk, the description does not accurately represent what this supplied code actually does.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 12)May include surrounding context.

md
- `scripts/pretty_markdown_to_html.py` for better-looking Markdown to HTML output

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 32)May include surrounding context.

md
- `scripts/pretty_markdown_to_html.py` for better-looking Markdown to HTML output

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 89)May include surrounding context.

md
- `scripts/pretty_markdown_to_html.py` for better-looking Markdown to HTML output

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 97)May include surrounding context.

md
- `scripts/pretty_markdown_to_html.py` for better-looking Markdown to HTML output

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 119)May include surrounding context.

md
- `scripts/pretty_markdown_to_html.py` for better-looking Markdown to HTML output

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 13)May include surrounding context.

md
- `scripts/html_to_markdown.mjs` for stronger HTML to Markdown conversion, URL fetching, cleanup profiles, metadata, and reports

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 52)May include surrounding context.

md
- `scripts/html_to_markdown.mjs` for stronger HTML to Markdown conversion, URL fetching, cleanup profiles, metadata, and reports

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 98)May include surrounding context.

md
- `scripts/html_to_markdown.mjs` for stronger HTML to Markdown conversion, URL fetching, cleanup profiles, metadata, and reports

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 120)May include surrounding context.

md
- `scripts/html_to_markdown.mjs` for stronger HTML to Markdown conversion, URL fetching, cleanup profiles, metadata, and reports

Known Vulnerable Dependency: js-yaml==3.14.2 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
97% confidence
Finding

js-yaml 3.14.2 is flagged for multiple algorithmic complexity issues involving merge keys and object-map resolution. This skill depends on gray-matter, which commonly parses user-controlled front matter from Markdown files, so crafted input could cause significant CPU exhaustion during ingestion or batch conversion.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: linkify-it==5.0.0 — 2 advisory(ies): CVE-2026-48801 (LinkifyIt#match scan loop has quadratic algorithmic complexity); CVE-2026-59887 (linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on at)

High
Category
Supply Chain
Confidence
95% confidence
Finding

linkify-it 5.0.0 is used by markdown-it to detect links in Markdown text and is reported vulnerable to quadratic-time scans. Because this skill renders potentially untrusted Markdown into HTML, specially crafted text can drive CPU-intensive parsing and create a practical denial-of-service condition in interactive or batch workflows.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.20.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises behaviors that imply file read/write and network access, but it does not declare any explicit tool scope such as allowed tools or permissions. That makes the operational boundary unclear and can lead an agent to invoke broader capabilities than a user expects, especially for URL fetching and writing converted outputs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill explicitly promotes converting URLs and batch-processing content into local Markdown files without clearly warning that it will fetch remote content and write artifacts to disk. In an agent setting, this can cause unintended network access, ingestion of untrusted content, and silent creation or overwrite of local files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script fetches arbitrary user-supplied URLs and follows redirects, which enables outbound network access to attacker-chosen destinations. In an agent/skill context, this can be abused for SSRF-like behavior, internal network probing, or unintended access to sensitive services if the runtime has network reachability beyond the user’s expectation.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest describes a Markdown/HTML conversion skill, including a 'Node pipeline' for HTML-to-Markdown, but it does not indicate that the skill will execute external system binaries. Spawning pandoc is a materially different capability from in-process conversion because it depends on host-level command execution rather than ordinary parsing/transformation logic.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The generated document always sets <html lang="zh-CN">, which imposes a specific language/locale on all output regardless of the user's input or preferences. This is a natural-language policy issue because the file provides no opt-in, override, or documented region-specific justification for forcing that locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

Several usage examples are written in Chinese while the rest of the document is in English, which creates an implicit language preference without opt-in or justification. This can violate language or locale policy when skills should avoid forcing a specific language unexpectedly.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: @mozilla/readability==0.5.0 — 1 advisory(ies): CVE-2025-2792 (@mozilla/readability Denial of Service through Regex)

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The lockfile pins @mozilla/readability to 0.5.0, and the reported advisory is a regex-based denial-of-service issue. In this skill's context, readability is used to parse and clean untrusted HTML/article content, so an attacker-controlled page or HTML input could trigger excessive CPU consumption during conversion.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: markdown-it==14.1.1 — 1 advisory(ies): CVE-2026-48988 (markdown-it: Quadratic complexity DoS in smartquotes rule via replaceAt string o)

Low
Category
Supply Chain
Confidence
83% confidence
Finding

markdown-it 14.1.1 is flagged for a quadratic-complexity smartquotes rule issue. Since this skill explicitly processes untrusted Markdown, maliciously crafted content may cause elevated CPU usage during rendering, though the impact is limited to denial of service rather than code execution or data compromise.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This manifest file describes the skill's capabilities in very general terms but does not indicate what specific user phrases, contexts, or constraints should activate it. For manifest files, missing specificity on trigger scope can lead to unintended invocation because the description overlaps with common content-conversion requests.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
85% confidence
Finding

Using a caret range for @mozilla/readability allows installs to float to newer compatible releases, which reduces build reproducibility and can introduce unreviewed dependency changes. In a content-processing skill that handles untrusted HTML, dependency drift increases supply-chain risk because parsing behavior and security posture may change between installs.

Content

Scanner excerpt · package.json (reported line 12)May include surrounding context.

json
"md2html:help": "node scripts/markdown_to_html.mjs --help"
  },
  "dependencies": {
    "@mozilla/readability": "^0.5.0",
    "gray-matter": "^4.0.3",
    "jsdom": "^26.0.0",
    "markdown-it": "^14.1.0",

Known Vulnerable Dependency: @mozilla/readability==0.5.0 — 1 advisory(ies): CVE-2025-2792 (@mozilla/readability Denial of Service through Regex)

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency @mozilla/readability version 0.5.0 is flagged with a known denial-of-service advisory involving regex processing. This skill explicitly ingests HTML and may process untrusted documents or URLs, so an attacker could supply crafted content that consumes excessive CPU and degrades availability.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
85% confidence
Finding

Using a caret range for gray-matter permits non-identical dependency resolution across environments, which weakens reproducibility and can introduce unreviewed upstream code changes. While not directly exploitable on its own, this is a genuine supply-chain hygiene weakness.

Content

Scanner excerpt · package.json (reported line 13)May include surrounding context.

json
},
  "dependencies": {
    "@mozilla/readability": "^0.5.0",
    "gray-matter": "^4.0.3",
    "jsdom": "^26.0.0",
    "markdown-it": "^14.1.0",
    "markdown-it-footnote": "^4.0.0",