T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/toutiao_publish.py:341
- Finding
- JavaScript Injection Through User-Controlled Post Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/toutiao_publish.py:341-350` **Vulnerability Type**: Browser-context JavaScript injection **Risk Level**: High ### Vulnerable Code ```python js_content = content.replace('&', '&').replace('<', '<').replace('>', '>').replace('\n', '<br>') page.evaluate(f''' () => {{ const editor = document.querySelector('div[contenteditable="true"]'); if (editor) {{ editor.innerHTML = `{js_content}`; editor.dispatchEvent(new Event('input', {{ bubbles: true }})); editor.dispatchEvent(new Event('change', {{ bubbles: true }})); }} }} ''') ``` ### Technical Analysis The post content is controlled through a positional command-line argument or a user-selected file. Although the code replaces HTML metacharacters, it interpolates the resulting value directly into a JavaScript template literal passed to `page.evaluate()`. HTML escaping does not make data safe for a JavaScript template-literal context. In particular, the code does not escape backticks, backslashes, or `${...}` template expressions. An attacker can therefore supply content that terminates the template literal or introduces a template expression, causing arbitrary JavaScript to execute in the authenticated Toutiao page. The injected code executes inside the browser origin rather than as native operating-system code. Nevertheless, it inherits access to the page DOM and the authenticated web session available to scripts executing in that origin. ### Attack Path 1. An attacker convinces the user or calling agent to publish attacker-controlled text, or supplies a post-content file. 2. The content contains a JavaScript template-literal payload using a backtick or `${...}` expression. 3. The script performs HTML escaping, but the JavaScript control characters remain intact. 4. The content is inserted into the Python f-string used to construct the `page.evaluate()` program. 5. Playwr ...[truncated 833 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not construct executable JavaScript by interpolating post content. Pass untrusted data as a separate Playwright argument or use locator text-entry APIs. A safer pattern is: ```python page.evaluate( """({editor, content}) => { editor.innerText = content; editor.dispatchEvent(new Event('input', {bubbles: true})); editor.dispatchEvent(new Event('change', {bubbles: true})); }""", { "editor": input_box.element_handle(), "content": content, }, ) ``` Where supported by the editor, prefer `input_box.fill(content)` or `input_box.press_sequentially(content)`. Avoid assigning untrusted data to `innerHTML`; use `innerText` or `textContent` unless HTML formatting is explicitly required. Add regression tests containing backticks, backslashes, `${...}` expressions, HTML tags, Unicode text, and multiline input to verify that all supplied content remains data and cannot affect JavaScript syntax. ]]>
