Back to skill

Security audit

Html Markdown Converter

Security checks for vulnerabilities and agentic risk

Overview

This is a real HTML and Markdown converter, but it needs review because it can fetch arbitrary URLs and generate active HTML without clear safety limits.

Review before installing in shared or sensitive environments. Use it only with trusted URLs and trusted Markdown, avoid attacker-provided URL lists, do not publish generated HTML from untrusted Markdown without sanitizing it first, and prefer a pinned dependency lockfile. The unrelated automotive reference links should also be removed or justified.

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:205
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); } } ``` The function is reached using user-controlled values in both single-URL and URL-list modes: ```js 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'); } ``` ```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); ``` ### Technical Analysis The `--url` argument and every entry in a `--url-list` file are passed directly to `fetch()`. The implementation does not validate the URL scheme, destination hostname, resolved IP address, destination port, or redirect destination. Although the documentation presents HTTPS URLs, the code does not enforce that restriction. The fetch operation also uses `redirect: 'follow'`, so an initially public URL can redirect to a loopback, private-network, link-local, or cloud metadata address. The timeout limits request duration but does not prevent unauthorized network access. The response body is returned as text, converted to Markdown, and written to an attacker-selected output location. ### Attack Path 1. An attacker supplies a URL through `--url` or pl ...[truncated 1431 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/markdown_to_html.mjs:108
Finding

Raw Markdown HTML Passthrough Enables Stored Cross-Site Scripting

Content
View full analysis
${CSS[opts.theme] || CSS.light}` : ''; return ` ${String(title).replace(/</g,'<')} ${css} ${body} `; } ``` ### Technical Analysis The Markdown parser is initialized with `html:true`, which instructs `markdown-it` to preserve raw HTML from the input. The rendered body is then inserted directly into the generated document without an HTML sanitization step. Consequently, untrusted Markdown can include active browser content such as: ```html ``` It can also contain event-handler attributes, malicious iframes, active SVG content, or dangerous URL schemes. The limited escaping applied to the document title does not protect the generated body. The issue affects both `--markdown` input and Markdown files processed through single-file or recursive batch modes. Returning a fragment with `--standalone false` does not remove the vulnerability if that fragment is inserted into another web page. ### Attack Path 1. An attacker creates a Markdown document containing executable raw HTML or dangerous HTML attributes. 2. A user or automated workflow processes the document with `markdown_to_html.mjs`. 3. `markdown-it` pre ...[truncated 1173 chars]
Remediation
View remediation
`, quotation marks, and apostrophes. 7. Add security tests using script tags, image error handlers, SVG payloads, iframe content, and dangerous link schemes. 8. Clearly document whether generated HTML is safe to publish and whether untrusted Markdown is supported. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/html_to_markdown.mjs:268
Finding

Incomplete YAML Escaping Allows Frontmatter Injection

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (20)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/html_to_markdown.mjs \

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/html_to_markdown.mjs \

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/html_to_markdown.mjs \

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/html_to_markdown.mjs \

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill explicitly supports fetching remote URLs, but the manifest shown in SKILL.md does not declare any tool scope or allowed-tools boundaries for that network capability. This creates an authorization and transparency gap: an agent may invoke networked behavior without clearly declaring or constraining it, increasing the risk of unintended external requests, SSRF-like access paths, or policy bypass in environments that rely on manifest-declared permissions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This script can fetch arbitrary remote content via --url/--url-list and writes converted markdown and optional JSON reports to disk, but the help text only describes usage and does not disclose privacy or system-impact implications. Because these are safety-relevant operations in a general-purpose converter, users are not explicitly warned that invoking the script may transmit requests to external hosts and overwrite/create files.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes a document conversion utility for local files, URLs, and batch processing, but does not mention spawning external programs. Using spawn('pandoc', ...) gives the skill OS-level process execution capability, which is broader than the stated conversion role and not obviously required because the script already contains an in-process conversion path via Turndown.

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 HTML always uses lang="zh-CN", which forces a specific language/locale regardless of the user's content or preferences. This is a natural-language policy concern because the skill does not offer opt-in, configuration, or justification for the locale restriction.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The automotive/VIN/EPC references are unrelated to an HTML↔Markdown conversion skill and introduce suspicious, unjustified external service promotion into the documentation. While not directly executable, irrelevant links in a skill can socially steer users or downstream agents toward unnecessary third-party services, which is a supply-chain and trust-boundary concern made more suspicious because the references do not match the declared skill purpose.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency uses a caret range instead of an exact pinned version, which weakens build reproducibility and makes it harder to verify whether the resolved package is affected by known vulnerabilities. In a skill that processes untrusted HTML content, supply-chain drift increases security uncertainty even if this line alone is not an immediately exploitable flaw.

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",

Unverifiable Dependency: @mozilla/readability has 1 known advisory(ies) (CVE-2025-2792 (@mozilla/readability Denial of Service through Regex)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The manifest references @mozilla/readability without an exact version, and there is a cited advisory for a regex-based denial of service affecting some releases. Because this skill is explicitly intended to process HTML and web content, an attacker could potentially supply crafted input that triggers excessive CPU consumption if a vulnerable version is installed.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

Using an unpinned version range for gray-matter allows different installations to resolve to different package versions over time, reducing reproducibility and complicating vulnerability assessment. This is a supply-chain hygiene issue rather than direct malicious logic in the manifest.

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",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The jsdom dependency is not pinned to a single exact release, so future installs may silently pick up different versions with different security properties. Because this skill handles HTML and DOM parsing, dependency-version uncertainty is somewhat more sensitive than in a non-parser package.

Content

Scanner excerpt · package.json (reported line 14)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",
    "markdown-it-task-lists": "^2.1.1",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

markdown-it is declared with a caret range, so the installed version may vary and may or may not include fixes for parser-related denial-of-service issues. Since the skill converts potentially attacker-controlled Markdown/HTML, parser dependency drift raises the risk of consuming a vulnerable release.

Content

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

json
"@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",
    "markdown-it-task-lists": "^2.1.1",
    "turndown": "^7.2.0",

Unverifiable Dependency: markdown-it has 4 known advisory(ies) (CVE-2026-2327 (markdown-it is has a Regular Expression Denial of Service (ReDoS)); CVE-2026-48988 (markdown-it: Quadratic complexity DoS in smartquotes rule via replaceAt string o); CVE-2022-21670 (Uncontrolled Resource Consumption in markdown-it) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding

markdown-it has multiple known denial-of-service style advisories, and the use of an unpinned range makes it impossible to confirm from this manifest whether the deployed version is safe. This is more concerning in this skill than in a generic utility because Markdown conversion is a core feature and likely processes attacker-controlled content.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

An unpinned markdown-it-footnote version introduces supply-chain uncertainty and undermines reproducible builds. While the impact is indirect, plugins in a content-processing pipeline can expand attack surface if a later resolved version contains vulnerable parsing behavior.

Content

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

json
"gray-matter": "^4.0.3",
    "jsdom": "^26.0.0",
    "markdown-it": "^14.1.0",
    "markdown-it-footnote": "^4.0.0",
    "markdown-it-task-lists": "^2.1.1",
    "turndown": "^7.2.0",
    "turndown-plugin-gfm": "^1.0.2"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The markdown-it-task-lists dependency is specified as a version range, allowing non-deterministic resolution across environments. In text-conversion tooling, parser/plugin inconsistency can produce both security uncertainty and inconsistent output handling.

Content

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

json
"jsdom": "^26.0.0",
    "markdown-it": "^14.1.0",
    "markdown-it-footnote": "^4.0.0",
    "markdown-it-task-lists": "^2.1.1",
    "turndown": "^7.2.0",
    "turndown-plugin-gfm": "^1.0.2"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

turndown is unpinned, which permits future installations to resolve to different code than was originally tested. For a converter operating on untrusted HTML, this reduces confidence that parser and transformation behavior remains safe and reviewable.

Content

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

json
"markdown-it": "^14.1.0",
    "markdown-it-footnote": "^4.0.0",
    "markdown-it-task-lists": "^2.1.1",
    "turndown": "^7.2.0",
    "turndown-plugin-gfm": "^1.0.2"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The turndown-plugin-gfm dependency uses a caret range, creating the same reproducibility and supply-chain verification weakness as the other dependencies. Plugin code in a document-conversion path should be tightly versioned to keep behavior and security posture stable.

Content

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

json
"markdown-it-footnote": "^4.0.0",
    "markdown-it-task-lists": "^2.1.1",
    "turndown": "^7.2.0",
    "turndown-plugin-gfm": "^1.0.2"
  }
}

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The CLI help is otherwise written in English, but the --content-mode description inserts Chinese-only text (正文提取, 尽量保留全文结构) with no opt-in or locale selection. This creates a language/locale policy issue because the tool presents a fixed language choice rather than respecting user language expectations.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/html_to_markdown.mjs:338