Back to skill

Security audit

Html To Pdf

Security checks for vulnerabilities and agentic risk

Overview

This HTML-to-PDF skill does what it claims, but it runs caller-supplied HTML in Chromium with the browser sandbox disabled by default and has weak output-path controls.

Review before installing. Use this only on trusted HTML or inside a disposable/containerized environment, remove or opt in explicitly to --no-sandbox, pin dependencies with a lockfile, and avoid running the font setup or converter under a privileged account. Be careful with output paths because existing files may be overwritten.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/html-to-pdf.mjs:20
Finding
Chromium Sandbox Is Unconditionally Disabled<![CDATA[ ## Vulnerability Details **File Location**: `scripts/html-to-pdf.mjs:20-23` **Vulnerability Type**: Unsafe browser security configuration **Risk Level**: High ### Vulnerable Code ```javascript const CHROME_ARGS = [ '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--font-render-hinting=none', '--enable-font-antialiasing' ]; ``` The arguments are subsequently used whenever Chromium is launched: ```javascript browser = await puppeteer.launch({ executablePath: CHROME_PATH, headless: true, args: CHROME_ARGS }); ``` ### Technical Analysis The script opens caller-supplied HTML in Chromium and allows the document's JavaScript and network resources to execute. Chromium is always launched with `--no-sandbox`, removing a major security boundary intended to contain a compromised renderer process. If the HTML itself, an embedded script, or a remotely loaded dependency exploits a vulnerability in the installed Chromium version, disabling the sandbox can make it substantially easier for the exploit to affect the host under the privileges of the account running this Skill. Although `SKILL.md` acknowledges that `--no-sandbox` is unsuitable for multi-tenant environments, the unsafe option is enabled by default rather than requiring an explicit opt-in. ### Attack Path 1. An attacker supplies a malicious HTML file or modifies a legitimate HTML file processed by the Skill. 2. The script launches Chromium with `--no-sandbox`. 3. Puppeteer navigates to the local HTML file and executes its active content. 4. The document or one of its remote dependencies exploits a vulnerability in the installed Chromium version. 5. Because the browser sandbox is disabled, an important containment layer is unavailable. 6. Successful exploitation can execute code or access resources with the privileges of the user running the conversion. This path depends on a suitable Chromium vulnerability; ordinary page JavaScript alone does not directly grant host code execu ...[truncated 493 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--no-sandbox` from the default Chromium arguments. 2. Run Chromium under a dedicated, unprivileged operating-system account. 3. If sandbox disabling is required in a narrowly constrained environment, require an explicit command-line or environment-variable opt-in and display a prominent warning. 4. Reject sandbox-disabled execution when running as root or in a multi-tenant service. 5. Process untrusted HTML inside an isolated container or virtual machine with: - A read-only filesystem where possible - A dedicated temporary output directory - No access to host credentials or sensitive mounts - Restricted outbound networking - CPU, memory, and execution-time limits 6. Keep Chromium patched and use a controlled, reviewed browser version. 7. Consider blocking remote resource loading unless it is explicitly required. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/html-to-pdf.mjs:31
Finding
Output Directory Allowlist Can Be Bypassed Through Prefix Matching<![CDATA[ ## Vulnerability Details **File Location**: `scripts/html-to-pdf.mjs:31-40` **Vulnerability Type**: Improper path validation **Risk Level**: Medium ### Vulnerable Code ```javascript // 安全路径白名单:仅允许写入这些目录的父级 const SAFE_PARENTS = [ process.env.HOME, '/tmp', process.cwd() ].filter(Boolean); function isSafePath(p) { return SAFE_PARENTS.some(dir => resolve(p).startsWith(dir)); } ``` The result controls whether a caller-supplied output path is accepted: ```javascript pdfPath = resolve(outRaw); if (!isSafePath(pdfPath)) { console.error('❌ 输出路径不在安全白名单内'); console.error(' 安全路径: HOME(' + process.env.HOME + '), /tmp, 当前目录(' + process.cwd() + ')'); console.error(' 建议: 将 PDF 输出到上述路径,或使用不指定输出参数(默认输出到输入文件同目录)'); process.exit(1); } ``` The accepted path is later written directly: ```javascript writeFileSync(pdfPath, pdf); ``` ### Technical Analysis The allowlist uses a raw string-prefix comparison rather than checking whether the output is actually contained within an approved directory. For example, because `/tmp` is approved, a resolved path such as `/tmp-escape/output.pdf` also begins with `/tmp` and therefore passes validation. Similarly, if `/home/alice` is approved through `HOME`, `/home/alice-other/output.pdf` is incorrectly treated as being inside `/home/alice`. The validation also does not resolve symlinks for an existing destination path or its parent directory. Consequently, an apparently approved path could traverse a symlink and cause the write to occur elsewhere. ### Attack Path 1. An attacker can influence the second command-line argument used as the PDF output path. 2. The attacker selects a path outside an approved directory that shares its string prefix, such as `/tmp-escape/target.pdf`. 3. `resolve()` normalizes the path, but `startsWith('/tmp')` still returns `true`. 4. `isSafePath()` accepts the destination. 5. The generated PDF is passed to `writeFileSync()`. 6. If operating-system permissions permit the write, ...[truncated 729 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce directory boundaries instead of using an unqualified prefix comparison. For example: ```javascript import { isAbsolute, relative, resolve } from 'path'; function isWithin(parent, candidate) { const root = resolve(parent); const target = resolve(candidate); const rel = relative(root, target); return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel)); } function isSafePath(candidate) { return SAFE_PARENTS.some(parent => isWithin(parent, candidate)); } ``` 2. Resolve the real path of the destination parent with `realpath()` or `realpathSync()` before validation to address symlink traversal. 3. Create and validate a dedicated output directory instead of allowing broad writes throughout `HOME`, `/tmp`, and the current working directory. 4. Refuse to overwrite an existing file by default. Use an exclusive creation mode such as `flag: 'wx'`, or require an explicit overwrite option. 5. Revalidate the destination immediately before writing to reduce time-of-check/time-of-use risks. 6. Where feasible, open the destination through a safely validated directory handle rather than trusting a path string. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:87
Finding
Installation Instructions Use Unpinned npm Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:87-89` **Vulnerability Type**: Unpinned third-party dependencies **Risk Level**: Low ### Vulnerable Code ```bash npm install puppeteer-core pdf-lib ``` ### Technical Analysis The documented installation command does not specify reviewed package versions, and the project does not include a lockfile or integrity metadata in the audited directory. As a result, users following the instructions install whichever versions of `puppeteer-core`, `pdf-lib`, and their transitive dependencies are selected by npm at installation time. Those versions can differ from the dependencies originally reviewed or tested by the project author. This creates a non-reproducible supply-chain boundary. A future compromised release, malicious transitive dependency, or incompatible update could introduce behavior that is absent from the audited Skill. There is no evidence in the audited project that either named package is malicious. The issue is the absence of version and integrity controls. ### Attack Path 1. A maintainer account, package release, or transitive dependency in the relevant npm dependency chain is compromised. 2. A malicious or vulnerable version is published under a dependency range selected by an unpinned installation. 3. A user follows the documented `npm install puppeteer-core pdf-lib` command. 4. npm resolves and downloads the affected current package graph. 5. Package installation hooks or imported runtime code execute with the privileges of the user running npm or the converter. This attack path requires a compromise or unsafe release in the upstream dependency chain. ### Impact Assessment The potential impact is determined by the behavior of the compromised dependency and the privileges of the installing or executing user. It could include arbitrary code execution during installation or runtime, access to local files and credentials, or unauthorized network activity. The current finding do ...[truncated 174 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a `package.json` containing exact, reviewed dependency versions. 2. Generate and commit a `package-lock.json`. 3. Instruct users and automation to install with `npm ci` rather than an unpinned `npm install` command. 4. Review lockfile changes as part of every dependency update. 5. Run dependency vulnerability and provenance checks in continuous integration. 6. Use npm integrity metadata and a trusted package registry. 7. Disable installation scripts where compatible with the selected dependency graph, or review every package that requires lifecycle scripts. 8. Establish a regular update process so pinned versions receive deliberate, tested security upgrades rather than remaining outdated indefinitely. ]]>
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Ae1

High
Category
analysis-evasion
Content
node scripts/html-to-pdf.mjs report.html
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/html-to-pdf.mjs report.html
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/html-to-pdf.mjs report.html
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/html-to-pdf.mjs report.html
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/html-to-pdf.mjs report.html
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/html-to-pdf.mjs report.html
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The description states the tool renders HTML to '纯中文 PDF', which imposes a language constraint in natural-language documentation. The file does not present this as an optional mode or offer a user language choice, so it appears to enforce a specific language/locale without opt-in.

Session Persistence

Medium
Category
Rogue Agent
Content
**方法 A:从 Windows 复制(WSL 环境)**

```bash
mkdir -p ~/.fonts
cp "/mnt/c/Windows/Fonts/Noto Sans SC (TrueType).otf" ~/.fonts/
cp "/mnt/c/Windows/Fonts/msyh.ttc" ~/.fonts/
cp "/mnt/c/Windows/Fonts/seguiemj.ttf" ~/.fonts/
Confidence
81% confidence
Finding
The skill instructs users to copy fonts into ~/.fonts and rebuild the font cache, which creates persistent changes to the user's environment outside the immediate task. Persistent modification of user directories can have unintended side effects, survive across sessions, and in shared or managed environments may violate change-control expectations.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The title and all instructional content in this file are presented exclusively in Chinese, with no indication that users may choose another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern.

Static analysis

No suspicious patterns detected.