T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:45
- Finding
- User-Controlled Prompt Interpolation into Browser JavaScript<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 45–60 **Vulnerability Type**: JavaScript injection through unsafe string interpolation **Risk Level**: High ### Vulnerable Code ```js () => { const ta = document.querySelector('textarea'); if (!ta) return { ok: false, reason: 'no textarea' }; const text = 'PROMPT_HERE'; const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set; setter.call(ta, text); ta.dispatchEvent(new Event('input', { bubbles: true })); ta.dispatchEvent(new Event('change', { bubbles: true })); return { ok: true, valueLength: ta.value.length }; } ``` ### Technical Analysis The skill instructs the agent to replace `PROMPT_HERE` with the image prompt and execute the resulting source using browser `evaluate`. The prompt is placed inside a single-quoted JavaScript string without requiring escaping, serialization, or argument binding. A malicious prompt containing a single quote followed by JavaScript syntax can terminate the intended string and inject additional statements. The injected code would execute in the context of the authenticated Doubao page. For example, a prompt shaped like the following could escape the string if inserted verbatim: ```text '; /* attacker-controlled JavaScript */ // ``` The precise capabilities of injected code depend on the browser automation environment and Doubao's page security controls. It could access page-visible content, inspect conversations rendered in the DOM, initiate same-origin actions, or send browser requests. Cookies protected with `HttpOnly` would not be directly readable, but the active authenticated session could still potentially be abused through same-origin requests. ### Attack Path 1. An attacker supplies or influences the image-generation prompt. 2. The agent follows the documented fallback and substitutes the prompt directly for `PROMPT_HERE`. 3. The prompt closes the single-quoted JavaScript string and ap ...[truncated 951 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Never concatenate or interpolate the prompt into executable JavaScript source. - Pass the prompt as a separate argument supported by the browser evaluation API. For example: ```js (prompt) => { const ta = document.querySelector('textarea'); if (!ta) return { ok: false, reason: 'no textarea' }; const setter = Object.getOwnPropertyDescriptor( window.HTMLTextAreaElement.prototype, 'value' ).set; setter.call(ta, prompt); ta.dispatchEvent(new Event('input', { bubbles: true })); ta.dispatchEvent(new Event('change', { bubbles: true })); return { ok: true, valueLength: ta.value.length }; } ``` - If argument passing is unavailable, serialize the value with a trusted serializer such as `JSON.stringify` before constructing the expression. Do not implement ad hoc quote escaping. - Explicitly state in the skill instructions that user input must never be substituted directly into JavaScript, PowerShell, Python, shell, or other executable source. - Add test cases containing quotes, backslashes, newlines, template-literal characters, and JavaScript fragments to verify that prompts remain data rather than code. ]]>
