Back to skill

Security audit

md2pdf

Security checks for vulnerabilities and agentic risk

Overview

This Markdown-to-PDF skill is mostly coherent, but it renders user documents in unsandboxed, network-capable Chrome while claiming offline/no-network behavior.

Install only if you will convert trusted Markdown/CSS or can run it in an isolated environment with network blocked. The skill should remove --no-sandbox, sanitize or disable raw HTML, restrict resource URLs, use a private temporary directory/profile, and correct its offline and dependency claims before routine use.

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/md2pdf.js:94
Finding

Unsanitized Markdown HTML Executes in a Chrome Process with Sandbox Disabled

Content
View full analysis
${escapeHtml(inputName)} ${pageCss} ${baseCss} ${extraCss} ${bodyHtml} `; ``` ```javascript // scripts/md2pdf.js:142-155 const chrome = findChrome(); // Default to no header/footer for clean preview export const pdfArgs = [ "--headless=new", "--disable-gpu", "--no-sandbox", "--run-all-compositor-stages-before-draw", "--virtual-time-budget=2000", "--print-to-pdf=" + outPath, "--no-pdf-header-footer", ]; pdfArgs.push("file://" + tmpHtml); try { execFileSync(chrome, pdfArgs, { stdio: ["ignore", "ignore", "pipe"], timeout: 60000 }); ``` The vendored Marked renderer passes raw HTML through unchanged: ```javascript // assets/marked.min.js:6 html(e,t){return e} ``` ### Technical Analysis The Markdown input is treated as untrusted text when read, but its trust level changes incorrectly after parsing. Marked permits embedded raw HTML and its default renderer returns HTML tokens without sanitization. The resulting `bodyHtml` is inserted directly into a complete HTML document. Consequently, Markdown can introduce active elements including `
Remediation
View remediation
``` The exact policy should be tested against the supported offline rendering features. 4. **Remove `--no-sandbox`.** - Run Chrome with its normal sandbox enabled. - If the environment cannot support sandboxed Chrome, fail with actionable setup guidance rather than silently removing the protection. - Consider running conversion in an additional operating-system sandbox or isolated container with no network access and a read-only filesystem. 5. **Restrict resource URLs.** - Permit only validated local files and explicitly supported `data:` resources. - Reject HTTP, HTTPS, FTP, `javascript:`, and other unnecessary schemes. - Resolve and validate local paths before use. 6. **Use a dedicated ephemeral Chrome profile.** - Supply a private temporary `--user-data-dir`. - Ensure it contains no user cookies, credentials, extensions, or existing browser state. - Delete it reliably after conversion. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/md2pdf.js:94
Finding

Markdown Conversion Can Perform Undisclosed External and Internal Network Requests

Content
View full analysis
${escapeHtml(inputName)} ${pageCss} ${baseCss} ${extraCss} ${bodyHtml} `; ``` ```javascript // scripts/md2pdf.js:142-155 const chrome = findChrome(); const pdfArgs = [ "--headless=new", "--disable-gpu", "--no-sandbox", "--run-all-compositor-stages-before-draw", "--virtual-time-budget=2000", "--print-to-pdf=" + outPath, "--no-pdf-header-footer", ]; pdfArgs.push("file://" + tmpHtml); try { execFileSync(chrome, pdfArgs, { stdio: ["ignore", "ignore", "pipe"], timeout: 60000 }); ``` Contradictory security claims include: ```markdown - 🔌 **Zero external dependencies**: `marked.js` is vendored, fully offline with no network access - 🚫 **No dangerous operations**: only reads input, writes temporary HTML, and makes no network requests ``` ```markdown ## Security Notes - Purely local conversion, no network requests, no credential access, and no external command injection - The only child process is Chrome headless PDF printing, with allowlisted hardcoded arguments ``` ```markdown - [x] Security self-audit passed (no network requests, no credential access, hardcoded arg ...[truncated 2758 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/md2pdf.js:125
Finding

Predictable Shared Temporary File Enables Symlink File Clobbering and Sensitive Data Residue

Content
View full analysis
"); process.exit(1); } else { outPath = path.resolve(path.dirname(args.input), inputName + ".pdf"); } ``` ```javascript // scripts/md2pdf.js:157-174 } catch (e) { // Chrome may exit nonzero despite success; validate the PDF instead if (!fs.existsSync(outPath) || fs.statSync(outPath).size === 0) { console.error("❌ PDF generation failed:", e.message); if (e.stderr) console.error(String(e.stderr).slice(0, 2000)); fs.rmSync(tmpHtml, { force: true }); process.exit(1); } } // 7. Clean temporary HTML and validate output fs.rmSync(tmpHtml, { force: true }); if (!fs.existsSync(outPath) || fs.statSync(outPath).size === 0) { console.error("❌ Output PDF is empty or missing:", outPath); process.exit(1); } const sizeKb = (fs.statSync(outPath).size / 1024).toFixed(1); console.log(`✅ Generated: ${outPath} (${sizeKb} KB)`); ``` ### Technical Analysis The temporary HTML filename is derived only from `Date.now()` and is created in the shared operating-system temporary directory. It is not created inside a private random directory, and `writeFileSync()` is not called with exclusive creation semantics. In a hostile multi-user environment, another local user can attempt to predict or race the millisecond-based filename and place a symbolic link at that location. Because the file is opened normally, the write can follow the symbolic link and overwrite a target file ...[truncated 2097 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • 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
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The documentation claims 'zero external dependencies' while requiring a locally installed Chrome binary and allowing an external CSS file. This is dangerous because users and reviewers may underestimate the skill's trust boundary, local executable dependency, and file-input surface, which can bypass expected scrutiny and lead to unsafe deployment assumptions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The documentation claims 'zero external dependencies' while requiring a locally installed Chrome binary and allowing an external CSS file. This is dangerous because users and reviewers may underestimate the skill's trust boundary, local executable dependency, and file-input surface, which can bypass expected scrutiny and lead to unsafe deployment assumptions.

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 20)May include surrounding context.

md
| Markdown 渲染 | `assets/marked.min.js` | MIT,vendored 离线 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| 编排 | `scripts/md2pdf.js` | Node 单脚本,无 npm 依赖 |

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
| 编排 | `scripts/md2pdf.js` | Node 单脚本,无 npm 依赖 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| 编排 | `scripts/md2pdf.js` | Node 单脚本,无 npm 依赖 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| 编排 | `scripts/md2pdf.js` | Node 单脚本,无 npm 依赖 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| 编排 | `scripts/md2pdf.js` | Node 单脚本,无 npm 依赖 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| 编排 | `scripts/md2pdf.js` | Node 单脚本,无 npm 依赖 |

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description says the skill is 'fully offline, zero external dependencies', which communicates that it operates without relying on external software. However, the same file's implementation notes state that PDF generation uses local Google Chrome and even list Chrome as a prerequisite, so the documentation overstates the skill's self-contained nature.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The natural-language content presents the skill entirely in Chinese and emphasizes Chinese-friendly behavior, but it does not offer users a language choice or explain that the skill is intentionally limited to a Chinese-speaking audience. Under the stated policy, forcing a specific language or locale without opt-in is a policy concern.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The header comment says the tool has '零外部依赖' while also stating 'Chrome 本机就有,' and the code later searches for and executes an external Chrome binary. That is an active contradiction in stated intent versus actual operational dependency.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script launches Chrome with the --no-sandbox flag while rendering attacker-controlled Markdown-derived HTML. Even though the input is local, rendered Markdown can include active HTML content, and disabling the browser sandbox removes a major containment boundary if browser rendering is exploited or if local-file behaviors are abused. In this skill’s context, the tool is explicitly meant to process arbitrary user documents, which makes the risk more significant rather than theoretical.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The description repeatedly positions the skill as '中文友好' and highlights Chinese-specific defaults such as a PingFang SC-first font stack. Under the policy rule for natural-language violations, this is a locale preference presented as the default experience without any mention of optional language/locale selection or that the tool is region-specific only.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The documented use of '--no-sandbox' weakens Chrome's process isolation during rendering of potentially untrusted Markdown-derived HTML. If malicious content triggers a browser exploit, disabling the sandbox can significantly increase host impact compared with a sandboxed renderer.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The file contains natural-language text stating the style is a built-in Chinese-friendly Markdown-to-PDF theme. This indicates a language/locale-specific default without any accompanying opt-in, alternative locale handling, or justification in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The markdown uses Chinese throughout, including the title, descriptions, and examples, but does not indicate that the skill is region-specific or that users may opt into this language. Under the natural-language policy rule, forcing a specific language without user choice can be a policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The entire skill document is written in Chinese and includes Chinese-specific guidance such as the title and the '中文字体' section, but it does not offer a language choice or explain that the skill is intentionally limited to Chinese-speaking users. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The generated document sets <html lang="zh-CN">, which forces a specific language/locale regardless of the user's input or preferences. The policy allows locale constraints only when users are given a choice or the constraint is clearly documented and justified, which is not evident in this file.

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/md2pdf.js:155