T09 · Insecure Skill Coding Practices
Warning
- Location
- detect-flicker.ts:39
- Finding
- CLI-Controlled JavaScript Injection in Browser Initialization Script## Vulnerability Details **File Location**: `detect-flicker.ts`, lines 39–44 and 99–102 **Vulnerability Type**: JavaScript injection through unsafe string interpolation **Risk Level**: Medium ### Vulnerable Code ```typescript async function detectFlicker(url: string, expectedTheme: string = 'dark'): Promise<FlickerResult> { const browser = await chromium.launch(); const context = await browser.newContext(); // Set theme preference BEFORE page loads await context.addInitScript(`localStorage.setItem('theme', '${expectedTheme}');`); ``` The interpolated value originates from a command-line argument: ```typescript // Main const url = process.argv[2] || 'http://localhost:3000'; const theme = process.argv[3] || 'dark'; detectFlicker(url, theme) ``` ### Technical Analysis The `expectedTheme` value is incorporated directly into a string containing executable JavaScript. It is not escaped or restricted to the intended values, such as `dark` and `light`. A malicious argument containing a quote and additional JavaScript can terminate the string passed to `localStorage.setItem` and append arbitrary statements. Playwright then installs the resulting source as an initialization script using `context.addInitScript`. That script executes whenever a page is created or navigated within the browser context. Because the injected script runs in the target page's browser context, it receives the origin-level capabilities available to ordinary page JavaScript. The vulnerability does not directly grant operating-system command execution, but it can expose page content and origin-accessible data. ### Attack Path 1. An attacker obtains control over, or influences, the third command-line argument passed to `detect-flicker.ts`. 2. The attacker supplies a value that closes the quoted theme value and appends JavaScript. 3. The value is inserted into the initialization-script source without validation or escaping. ...[truncated 1208 chars]
- Remediation
- ## Remediation Suggestions Do not construct executable JavaScript by concatenating or interpolating untrusted values. Pass the theme as a structured Playwright argument: ```typescript await context.addInitScript( theme => localStorage.setItem('theme', theme), expectedTheme ); ``` In addition, enforce an explicit allowlist before creating the browser context: ```typescript type Theme = 'dark' | 'light'; function parseTheme(value: string): Theme { if (value !== 'dark' && value !== 'light') { throw new Error('Theme must be either "dark" or "light"'); } return value; } const theme = parseTheme(process.argv[3] || 'dark'); ``` Apply both controls: the allowlist enforces the intended interface, while structured argument passing prevents source-code injection if accepted values are expanded later.
