T09 · Insecure Skill Coding Practices
- Location
scripts/download.py:83- Finding
JavaScript Injection in Generated Playwright Script Enables Arbitrary Command Execution
- Content
View full analysis
{{ const browser = await chromium.launch({{ headless: true }}); const context = await browser.newContext(); const page = await context.newPage(); // Navigate to URL await page.goto('{url}', {{ waitUntil: 'networkidle' }}); // Wait for content await page.waitForTimeout(2000); // Handle authentication if needed // (Would need credentials for institutional access) // Get PDF link or download directly const pdfLink = await page.$('a[href$=".pdf"]'); if (pdfLink) {{ const href = await pdfLink.getAttribute('href'); console.log(href); }} await browser.close(); }})(); ''' # Save and run script with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f: f.write(script) temp_path = f.name try: result = subprocess.run(['node', temp_path], capture_output=True, text=True) return result.stdout.strip() finally: os.unlink(temp_path) ``` ### Technical Analysis The `download_with_playwright` function inserts the caller-provided `url` directly into executable JavaScript source using a Python formatted string. The URL is placed between JavaScript single quotes without escaping or safe serialization: ```python await page.goto('{url}', ...) ``` An attacker can supply a value containing a single quote and additional JavaScript statements. This can terminate the intended string, alter the generated program, and invoke Node.js APIs such as `require('child_process')`. The generated source is written to a temporary `.js` file and executed with Node.js. Although `subprocess.run` uses an argument array and therefore does not itself invoke a she ...[truncated 1911 chars]- Remediation
View remediation
