ITADN

[Detail Bug] Screenshot rendering: XSS when prettifying text/plain API responses

#691Closeddetail-app[bot] 创建于 2026-03-02
D
detail-app[bot]commented
# Detail Bug Report https://app.detail.dev/org_06887db3-bf54-40ab-976d-46c66ab2b840/bugs/bug_ac4f2a30-ec5c-4f97-99d1-feb74772537e # Summary - **Context**: The `packages/screenshot/src/pretty/html.js` module generates HTML to display API responses (JSON/text) with syntax highlighting for screenshot capture. - **Bug**: User-controlled content from external API responses is directly embedded into HTML templates without HTML escaping, enabling Cross-Site Scripting (XSS) attacks. - **Actual vs. expected**: Content is inserted raw into the HTML using template literals, allowing execution of malicious JavaScript; it should be HTML-escaped before insertion. - **Impact**: Attackers can execute arbitrary JavaScript when users screenshot malicious APIs, potentially stealing sensitive data from the browser automation context or interfering with the screenshot process. # Code with Bug In `packages/screenshot/src/pretty/html.js`: ```javascript module.exports = (payload, { contentType, prism, theme }) => { const css = `${resetCSS}\n${theme}` const lang = language(contentType) const code = content(payload, contentType) // No HTML escaping return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> ${css} </head> <body id="screenshot"> <pre><code class="${lang}">${code}</code></pre> // <-- BUG 🔴 unescaped user content injected into HTML <script>${prism}</script> </body> </html>` } ``` # Explanation `code` can contain attacker-controlled API response text (notably for `contentType: 'text'`). It is interpolated directly into an HTML string passed to the browser, so any embedded HTML (e.g., `<script>`, `<img onerror=...>`, SVG) is parsed and can execute immediately. A partial defense exists elsewhere (`if (isHtmlContent(content)) return`), but `is-html-content` only detects content that *starts with* `<` (regex `/^\s*</`). Payloads like `"OK\n<script>...</script>"` bypass the check. Prism.js does not prevent exploitation because scripts/event handlers can run during initial HTML parsing before Prism sanitizes/highlights the code. ## Codebase Inconsistency `packages/screenshot/src/pretty/index.js` attempts to avoid HTML injection via: ```javascript if (isHtmlContent(content)) return ``` …but that check does not cover the common bypass where the response begins with non-`<` text. # Exploit Scenario An attacker controls an API endpoint that returns `text/plain` content containing a script tag or an HTML element with an event handler after some benign text (so it doesn’t start with `<`). When a user screenshots/prettifies that API response, the generated HTML executes the attacker’s JavaScript in the automation browser context. # Recommended Fix HTML-escape `content(payload, contentType)` before inserting it into the template (or refactor to set code via `textContent` rather than string interpolation). Example escape approach: ```javascript const code = escapeHtml(content(payload, contentType)) ``` # History This bug was introduced in commit 18ab1b4b. The commit added support for prettifying text/plain API responses in addition to JSON responses, and the refactor began interpolating raw strings into HTML without escaping.
关闭于 2026-05-17 0 条评论