T09 · Insecure Skill Coding Practices
- Location
api/browser/open-url.js:18- Finding
Shell Command Injection in the URL Opener
- Content
View full analysis
hostname === host || hostname.endsWith('.' + host)) } catch { return false } } async function openUrl(url) { if (!url) throw new Error('URL is required') if (!isAllowedUrl(url)) throw new Error(`URL not allowed: ${url}`) if (process.platform === 'darwin') { await execAsync(`open "${url}"`) } else if (process.platform === 'win32') { await execAsync(`start "" "${url}"`) } else { await execAsync(`xdg-open "${url}"`) } } ``` ### Technical Analysis The URL is interpolated directly into a command passed to `child_process.exec`. The hostname allowlist only validates the parsed protocol and hostname; it does not make the complete URL safe for use in a shell command. Shell metacharacters and command substitutions can remain in URL components such as the path or query string. Double quotes do not prevent command substitution on Unix-like shells. Equivalent metacharacter behavior also creates risk on Windows. The function is exported and can additionally be invoked through the command-line interface using `process.argv[2]`. Any attacker who can control the URL passed to this function can potentially reach the vulnerable shell sink. ### Attack Path 1. The attacker constructs an HTTPS URL whose hostname passes the `i.beautsgo.com` allowlist. 2. The attacker places shell syntax in a URL path, fragment, or query component. 3. The URL passes `isAllowedUrl` because only its protocol and hostname are checked. 4. `openUrl` interpolates the original untrusted string into an `open`, `start`, or `xdg-open` shell command. 5. The operating-system shell interprets th ...[truncated 622 chars]- Remediation
View remediation
