T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/birdx.js:613
- Finding
- Shell Command Injection Through an Unvalidated Username<![CDATA[ ## Vulnerability Details **File Location**: `scripts/birdx.js`, lines 613-617 **Vulnerability Type**: OS command injection **Risk Level**: Critical ### Vulnerable Code ```js async function resolveUsernameToId(username) { const handle = username.replace(/^@/, ''); try { const out = execSync(`bird user-tweets ${handle} -n 1 --json 2>/dev/null`, { timeout: 15000 }).toString().trim(); const data = JSON.parse(out); ``` ### Technical Analysis The `username` value originates from a positional command-line argument. Removing an optional leading `@` does not validate or escape the value. The resulting `handle` is interpolated directly into a command string passed to `execSync()`. Because the string form of `execSync()` invokes a shell, shell metacharacters contained in the username can introduce additional commands, pipelines, substitutions, or redirections. The vulnerable path is reachable through both the `followers` and `following` commands. The external command also redirects standard error through shell syntax, confirming that the command is deliberately interpreted by a shell rather than executed as a fixed executable with an argument array. ### Attack Path 1. An attacker persuades a user, automation agent, or service to invoke `birdx followers` or `birdx following` with an attacker-controlled username. 2. CLI parsing accepts the positional value without validating it as an X username. 3. `cmdFollowers()` or `cmdFollowing()` passes the value to `resolveUsernameToId()`. 4. `resolveUsernameToId()` interpolates the value into the `bird user-tweets ...` shell command. 5. Shell metacharacters in the supplied value alter the command structure. 6. The injected command executes with the privileges and environment of the user running `birdx`. For example, a value structurally equivalent to `validname; additional-command` would cause the shell to interpret the text following the semicolon as another command. ### Impact Assessment Successful ...[truncated 629 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not pass user-controlled data through a shell. 2. Replace `execSync()` with `execFileSync()` or `spawnSync()` and provide each argument separately: ```js const { execFileSync } = require('child_process'); function validateHandle(username) { const handle = username.replace(/^@/, ''); if (!/^[A-Za-z0-9_]{1,15}$/.test(handle)) { throw new Error('Invalid X username'); } return handle; } const handle = validateHandle(username); const out = execFileSync( 'bird', ['user-tweets', handle, '-n', '1', '--json'], { encoding: 'utf8', timeout: 15000, stdio: ['ignore', 'pipe', 'ignore'], } ).trim(); ``` 3. Enforce X's username character and length constraints before invoking any external program. 4. Resolve and validate the intended executable path where practical, rather than relying entirely on `PATH`. 5. Add regression tests containing spaces, semicolons, command substitutions, redirections, pipes, and newline characters, verifying that every invalid value is rejected. ]]>
