T09 · Insecure Skill Coding Practices
- Location
SKILL.md:69- Finding
JavaScript Injection Through Unsafe Prompt Interpolation
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 69–80
Vulnerability Type: JavaScript injection in a CDP runtime expression
Risk Level: HighVulnerable Code
javascript // Input prompt const prompt = '生成一只可爱的老虎头像,动漫风格'; await Runtime.evaluate({ expression: ` (function(){ const ta = document.querySelector('textarea'); if(!ta) return JSON.stringify({ok:false}); ta.value = '${prompt}'; ta.dispatchEvent(new Event('input', {bubbles:true})); return JSON.stringify({ok:true}); })() `, returnByValue: true });Technical Analysis
The workflow constructs JavaScript source code for
Runtime.evaluateby directly interpolatingpromptinto a single-quoted JavaScript string. No escaping, serialization, or separation between code and data is applied.Although the documented example initializes
promptwith a constant value, this value represents the image-generation prompt and would ordinarily be replaced with user-controlled input when the automation is used as intended. A prompt containing a single quote can terminate theta.valuestring. Additional JavaScript can then be inserted into the expression evaluated through the Chrome DevTools Protocol.Conceptually, an input shaped like the following demonstrates the injection boundary:
text '; /* attacker-controlled JavaScript */ //This transforms prompt data into executable code in the context of the authenticated Doubao page. The vulnerability is therefore not limited to malformed input or denial of service; it creates a browser-context code-execution primitive.
Attack Path
- An attacker supplies a crafted image-generation prompt to an application or agent implementing the documented workflow.
- The application assigns that untrusted input to
prompt. - The workflow inserts the prompt directly into the
expressiontemplate literal as part of `ta.value = '${ ...[truncated 1223 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not concatenate or interpolate untrusted prompt content into JavaScript source.
- Pass the prompt as a CDP argument using
Runtime.callFunctionOn, keeping executable code and untrusted data separate. - If an expression must be constructed, encode the value with
JSON.stringify(prompt)rather than surrounding it manually with quotes. - Validate that the prompt is a string and impose a reasonable length limit before sending it to the browser.
- Restrict CDP exposure to a trusted local interface and prevent untrusted processes from connecting to the remote-debugging port.
- Add security tests containing quotes, backslashes, template-literal characters, newlines, and representative injection strings.
A safer serialization-based implementation is:
javascript const serializedPrompt = JSON.stringify(prompt); await Runtime.evaluate({ expression: ` (function(){ const ta = document.querySelector('textarea'); if (!ta) return JSON.stringify({ok:false}); ta.value = ${serializedPrompt}; ta.dispatchEvent(new Event('input', {bubbles:true})); return JSON.stringify({ok:true}); })() `, returnByValue: true });Prefer a parameterized CDP call over source construction wherever the selected CDP API permits it.
