T09 · Insecure Skill Coding Practices
Error
- Location
- index.js:31
- Finding
- Shell Command Injection Through Unquoted CDP Arguments## Vulnerability Details **File Location**: `index.js`, lines 31-36 **Vulnerability Type**: OS command injection caused by unsafe shell command construction **Risk Level**: High ### Vulnerable Code ```javascript const cmd = ['node', CDP_SCRIPT, command, ...args]; const output = execSync(cmd.join(' '), { cwd: CDP_DIR, encoding: 'utf8', timeout: 30000 }); ``` ### Technical Analysis The `cdp()` function combines an executable, script path, command, and caller-supplied arguments into a single string using `cmd.join(' ')`. It then passes that string to `execSync()`, which evaluates the string through a system shell. Arguments reaching this sink include `targetId`, `selector`, `text`, `url`, and JavaScript `expression` values accepted by exported functions such as `click()`, `type()`, `navigate()`, and `evaluate()`. These values are neither validated nor safely separated from the command line. Consequently, shell metacharacters such as semicolons, command substitutions, redirections, and pipelines can terminate or alter the intended Node.js command. The construction also handles legitimate arguments containing spaces or quotation marks incorrectly. ### Attack Path 1. An attacker influences an argument passed to an exported skill operation, such as the URL supplied to `navigate()` or the expression supplied to `evaluate()`. 2. The exported operation forwards that value to `cdp()` as an element of `args`. 3. `cdp()` concatenates the argument into a shell command without quoting or escaping. 4. `execSync()` invokes the system shell to interpret the resulting command string. 5. Shell syntax embedded in the attacker-controlled argument executes an additional operating-system command. For example, an input structurally equivalent to: ```javascript navigate('abc123', 'https://example.invalid; id > /tmp/cdp-command-output') ``` causes the semicolon and following command to be interpreted by the shell rath ...[truncated 846 chars]
- Remediation
- ## Remediation Suggestions Avoid invoking a shell for argument-based process execution. Replace `execSync()` with `execFileSync()` or `spawnSync()` and pass each argument separately: ```javascript const { execFileSync } = require('child_process'); const output = execFileSync( process.execPath, [CDP_SCRIPT, command, ...args], { cwd: CDP_DIR, encoding: 'utf8', timeout: 30000, shell: false } ); ``` Additional hardening should include: 1. Restrict `command` to an explicit allowlist such as `list`, `shot`, `snap`, `html`, `click`, `type`, `nav`, `eval`, and `net`. 2. Validate target identifiers against the exact format emitted by Chrome CDP. 3. Apply reasonable length limits to selectors, text, URLs, and expressions to reduce denial-of-service exposure. 4. Validate navigation URLs against the intended schemes and destination policy. 5. Preserve arguments as discrete values; do not attempt to repair the issue solely through manual shell escaping. 6. Return sanitized error details so command failures do not unnecessarily expose sensitive paths or process output. 7. Add regression tests using spaces, quotation marks, semicolons, command substitutions, redirections, and newline characters.
