T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/html-to-pdf.mjs:133
- Finding
- Untrusted HTML Executes with Unrestricted Network Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/html-to-pdf.mjs`, lines 133-134 and 153-155 **Vulnerability Type**: Active-content execution and unrestricted browser networking **Risk Level**: Medium ### Vulnerable Code ```js const context = await browser.newContext({ viewport: { width, height }, deviceScaleFactor: 2 }); const page = await context.newPage(); ``` ```js await page.goto(pathToFileURL(inputAbs).href, { waitUntil: 'domcontentloaded', timeout: 30_000 }); await page.waitForLoadState('load', { timeout: 15_000 }).catch(() => {}); await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => {}); ``` ### Technical Analysis The converter accepts arbitrary HTML slide decks and opens them as active browser documents. The browser context does not disable JavaScript, and no request interception policy restricts the hosts, protocols, or network destinations that the document may contact. Consequently, scripts, images, stylesheets, fonts, iframes, and other active or passive resources in an attacker-controlled deck can initiate requests to: - Attacker-controlled Internet services - Services reachable only from the victim's network - Localhost services - Private-network addresses accessible from the conversion host The converter explicitly waits for document loading and network activity, providing embedded scripts with an execution window before PDF generation. Chromium's sandbox and same-origin policy reduce the likelihood of direct host compromise or reading arbitrary cross-origin responses, but they do not categorically prevent outbound requests, blind internal-service interactions, or disclosure of information already available to the malicious document. The project's stated purpose requires rendering HTML, but it does not inherently require arbitrary script execution or unrestricted networking. These capabilities should therefore be disabled by default or exposed only through explicit trusted-content options. ### Attack ...[truncated 1490 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Disable JavaScript by default** when static slide rendering permits it: ```js const context = await browser.newContext({ viewport: { width, height }, deviceScaleFactor: 2, javaScriptEnabled: false, }); ``` 2. **Implement a default-deny request policy** with `context.route('**/*', ...)`. Permit only: - The input HTML file - Explicitly approved files beneath the input deck directory - Deliberately configured font or asset hosts 3. **Block sensitive destinations**, including: - Loopback addresses - Link-local addresses - RFC 1918 private networks - Cloud metadata endpoints - Non-HTTP protocols not required by conversion 4. **Add explicit trust controls**, such as: - `--allow-javascript` - `--allow-remote-assets` - `--allow-host example.com` These options should be disabled by default and accompanied by clear warnings. 5. **Use process-level isolation** for untrusted decks: - Run Chromium as an unprivileged user - Use a container or sandbox with no sensitive mounts - Apply outbound firewall restrictions - Enforce CPU, memory, file-size, and execution-time limits 6. **Document the trust boundary** clearly. State that trusted mode executes scripts contained in the source deck and may contact network resources. ]]>
