Back to skill

Security audit

HTML 页面转图片

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its HTML-to-image purpose, but it needs Review because it renders caller-supplied HTML in an unsandboxed, network-enabled browser and ships a legacy script with automatic recursive deletion.

Install only if you will render trusted HTML or can run it in a tightly isolated environment with minimal filesystem access and restricted network egress. Avoid running the legacy convert-pages.js script unless you have checked the hard-coded output path, because it deletes that directory recursively before rendering. Prefer updating Puppeteer and its lockfile dependencies before 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
lib/convert-pages.js:45
Finding

Untrusted HTML Executes with Unrestricted Network Access in an Unsandboxed Browser

Content
View full analysis

Vulnerability Details

File Location: lib/convert-pages.js, lines 45-61
Vulnerability Type: Uncontained execution of active HTML content
Risk Level: High

Vulnerable code:

javascript
// 启动浏览器
browser = await puppeteer.launch({
  headless: true,
  args: ['--no-sandbox', '--disable-setuid-sandbox']
});

const page = await browser.newPage();

// 设置视口大小
await page.setViewport({
  width: pageWidth,
  height: pageHeight,
  deviceScaleFactor: 2 // 2x 分辨率,获得更清晰的图片
});

// 加载 HTML 内容
await page.setContent(htmlContent, {
  waitUntil: 'networkidle0'
});

Technical Analysis

The Skill accepts a caller-controlled HTML file and passes its contents to page.setContent(). By default, Chromium executes JavaScript contained in that document and permits it to initiate network requests. No request interception, destination allowlist, private-address filtering, or JavaScript restriction is applied.

At the same time, Chromium is launched with both --no-sandbox and --disable-setuid-sandbox. These flags remove an important browser-process isolation boundary. Rendering HTML requires a browser engine, but unrestricted active-content execution and removal of the browser sandbox exceed the minimum privileges needed to produce screenshots.

A hostile document can therefore:

  • Execute arbitrary browser-side JavaScript.
  • Transmit document data to an attacker-controlled endpoint.
  • Load attacker-controlled remote scripts and other resources.
  • Send requests to loopback, private-network, link-local, or cloud metadata addresses.
  • Perform blind cross-site request forgery against services reachable from the rendering host.
  • Attempt exploitation of browser vulnerabilities with reduced operating-system containment.

Browser same-origin controls may prevent JavaScript from reading some cross-origin responses, but they do not prevent all outbound or state-changing requests. A browser vulne ...[truncated 1428 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove --no-sandbox and --disable-setuid-sandbox, and configure the deployment environment so Chromium can run with its normal sandbox enabled.
  2. If JavaScript is not necessary for rendering, call page.setJavaScriptEnabled(false) before loading the document.
  3. Enable request interception and deny network requests by default. Allow only resource schemes and explicitly trusted domains required for rendering.
  4. Explicitly block loopback, private, link-local, multicast, and cloud metadata address ranges after DNS resolution. Revalidate redirects to prevent allowlist bypass.
  5. Consider rewriting remote resources into reviewed local assets so screenshot generation can run without network access.
  6. Enforce navigation, rendering, and request timeouts to limit denial-of-service conditions.
  7. Run the renderer as a dedicated unprivileged user in an isolated container or virtual machine with a read-only filesystem, restricted egress, bounded CPU and memory, and access only to the selected input and output locations.
  8. Document whether input HTML is trusted. If untrusted files are supported, add security-focused validation and containment tests.

T09 · Insecure Skill Coding Practices

Warning
Location
convert-pages.js:14
Finding

Legacy Script Recursively Deletes a Hard-Coded Directory at Module Load

Content
View full analysis

Vulnerability Details

File Location: convert-pages.js, lines 14-19
Vulnerability Type: Unsafe recursive filesystem deletion
Risk Level: Medium

Vulnerable code:

javascript
// 清空输出目录
import { rmSync } from 'fs';
if (existsSync(OUTPUT_DIR)) {
  rmSync(OUTPUT_DIR, { recursive: true, force: true });
}
mkdirSync(OUTPUT_DIR, { recursive: true });

Technical Analysis

The retained legacy script performs a recursive, forced deletion of OUTPUT_DIR as a top-level side effect. Consequently, the operation occurs immediately when the file is run or imported, before conversion succeeds and without confirmation.

The directory is derived from a hard-coded path outside the Skill directory. The script does not verify that the resolved target is an approved output directory, does not check for symbolic-link or deployment-layout hazards, and does not limit deletion to files previously generated by the Skill.

Clearing an output directory can be useful, but recursively deleting the entire directory is broader than the declared requirement to create screenshots. The destructive behavior is also not disclosed in the primary documented invocation flow.

Attack Path

  1. A user, automation process, or another module executes or imports the compatibility script.
  2. Top-level initialization resolves the hard-coded OUTPUT_DIR.
  3. If that directory exists, rmSync() recursively deletes all content with force: true.
  4. The deletion occurs before the HTML input is read or conversion success is established.
  5. Existing images or unrelated files stored beneath the target directory are irreversibly removed.

Impact Assessment

The operation can destroy every file and subdirectory under the resolved output path that the running account is permitted to delete. Its scope is limited by the operating-system permissions of that account, and the path is not directly caller-controlled in this script. Neverthe ...[truncated 261 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the obsolete script if compatibility is no longer required.
  2. Eliminate top-level destructive side effects. Place cleanup inside an explicitly invoked function.
  3. Require a separate, opt-in cleanup option rather than deleting output automatically.
  4. Resolve and canonicalize the target path, then verify that it is a child of a dedicated approved output root.
  5. Refuse deletion of filesystem roots, home directories, the project root, workspace roots, and any target outside the approved output location.
  6. Delete only files recorded as outputs from prior Skill runs instead of recursively removing the entire directory.
  7. Detect symbolic links and avoid traversing or deleting unexpected linked locations.
  8. Perform input validation before cleanup and preserve existing output if conversion cannot begin.
  9. Clearly document all destructive behavior and provide a dry-run or confirmation mechanism for direct command-line use.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (15)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
import { execute } from './index.js';

Known Vulnerable Dependency: basic-ftp==5.2.0 — 4 advisory(ies): GHSA-6v7q-wjvx-w8wg (basic-ftp: Incomplete CRLF Injection Protection Allows Arbitrary FTP Command Exe); CVE-2026-39983 (basic-ftp has FTP Command Injection via CRLF); CVE-2026-41324 (basic-ftp vulnerable to denial of service via unbounded memory consumption in Cl) +1 more

High
Category
Supply Chain
Confidence
96% confidence
Finding

The lockfile pins basic-ftp 5.2.0, and it is pulled in via get-uri/proxy handling in the Puppeteer dependency tree. If code paths ever process attacker-influenced FTP URLs or proxy/PAC-derived URIs, the cited command-injection and resource-consumption issues could be reachable; package-lock presence alone does not prove exploitability, but it does confirm a vulnerable version is shipped.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: extract-zip==2.0.1 — 2 advisory(ies): CVE-2026-19693 (extract-zip allows arbitrary file writes through symlink archive entries); CVE-2026-56876 (extract-zip unvalidated symlink path traversal)

High
Category
Supply Chain
Confidence
98% confidence
Finding

extract-zip 2.0.1 is present as a transitive dependency of @puppeteer/browsers, which downloads and unpacks browser archives during install/runtime workflows. Symlink/path-traversal flaws in archive extraction can lead to arbitrary file write outside the intended directory if a crafted archive is processed, making this especially relevant in software that fetches binaries automatically.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ip-address==10.1.0 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
83% confidence
Finding

ip-address 10.1.0 is included through socks proxy support. The listed issues are real for that package, but in this skill context the XSS portion is likely less relevant unless its HTML-formatting helpers are surfaced to users, while the address parsing inconsistency could matter if proxy or ACL logic relies on strict IP interpretation.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: js-yaml==4.1.1 — 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
93% confidence
Finding

js-yaml 4.1.1 is present via cosmiconfig, which Puppeteer can use for configuration discovery. The advisories describe CPU-exhaustion conditions from malicious YAML content, so if this skill or its environment loads attacker-controlled config files, parsing could become a denial-of-service vector; the risk is lower if only trusted local config is used.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: tar-fs==3.0.4 — 3 advisory(ies): CVE-2025-48387 (tar-fs can extract outside the specified dir with a specific tarball); CVE-2024-12905 (tar-fs Vulnerable to Link Following and Path Traversal via Extracting a Crafted ); CVE-2025-59343 (tar-fs has a symlink validation bypass if destination directory is predictable w)

High
Category
Supply Chain
Confidence
97% confidence
Finding

tar-fs 3.0.4 is included under @puppeteer/browsers, which handles browser package acquisition and extraction. Path traversal and symlink/link-following flaws in archive extraction can let a crafted tarball write outside the destination directory, so this is materially dangerous in a package that downloads and unpacks artifacts.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.16.0 — 3 advisory(ies): CVE-2024-37890 (ws affected by a DoS when handling a request with many HTTP headers); 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
91% confidence
Finding

ws 8.16.0 is present through puppeteer-core and is used for browser protocol communication. The cited issues are primarily denial-of-service and memory disclosure risks; exploitability depends on whether untrusted peers can interact with the WebSocket handling path, but shipping the known-vulnerable version still represents a real dependency risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code includes natural-language comments and console messages in Chinese, beginning with the configuration comment and continuing throughout the script. Under the policy, forcing a specific language without user opt-in can be a locale-policy violation when the skill is not clearly documented as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This file contains natural-language comments and console output exclusively in Chinese, including operational messages shown during execution. The policy requires avoiding forced language or locale unless the skill offers user opt-in or clearly documents a justified regional constraint, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language content of the skill forces a specific language for all users, and there is no indication that this is an intentional locale-specific skill or that alternative language support is available. Under the stated policy, language constraints should be opt-in or clearly justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file documents an operation that creates files in a user-specified directory, which can affect user data on disk. It describes the output location but does not include any caution about creating or potentially replacing files in that directory.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language comments and console messages are entirely in Chinese, including the primary usage description and example headings. This indicates a language-specific user experience without any visible opt-in, fallback, or justification that the skill is intended only for a Chinese-speaking or region-specific context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The package description is written entirely in Chinese, which indicates a language-specific skill description without any visible option for users to choose another language or locale. Under the policy, forcing a specific language without opt-in is a natural-language policy concern unless the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

Using a caret range for puppeteer allows newer minor/patch releases to be installed automatically, which can introduce supply-chain risk, unexpected behavior changes, or accidental ingestion of a compromised upstream release. In an agent skill context, this matters because Puppeteer drives a browser and often handles untrusted HTML/content, so dependency drift can affect both security posture and reproducibility.

Content

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

json
"author": "",
  "license": "MIT",
  "dependencies": {
    "puppeteer": "^21.6.1"
  }
}

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest description is written only in Chinese, and the file provides no indication that the skill is intended specifically for Chinese-speaking users or that language selection is optional. This can create a language/locale policy issue because the skill metadata presents a single language without user opt-in or documented regional justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.