T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/rotate.js:25
- Finding
- OS Command Injection in Image Rotation Wrapper<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rotate.js:25-43` **Vulnerability Type**: OS command injection through shell-string construction **Risk Level**: High ### Vulnerable Code ```js const args = parseArgs(process.argv.slice(2)); const input = args.input; const output = args.output || input.replace('.', '_rotated.'); const angle = args.angle || '0'; const scale = args.scale || '1.0'; if (!input) { console.error('Error: --input is required'); console.error('Usage: node rotate.js --input photo.jpg --output rotated.jpg --angle 90'); process.exit(1); } try { console.log(`🔄 Rotating image: ${input}`); console.log(` Angle: ${angle}°, Scale: ${scale}`); const cmd = `cli-anything-imutils rotate-cmd "${input}" "${output}" --angle ${angle} --scale ${scale}`; const result = execSync(cmd, { encoding: 'utf-8' }); ``` ### Technical Analysis The `input`, `output`, `angle`, and `scale` values originate from command-line arguments and are inserted into a command string passed to `child_process.execSync`. Because `execSync` executes the string through a system shell, shell operators embedded in an argument can be interpreted as command syntax. The `angle` and `scale` values are especially exposed because they are inserted without quoting or numeric validation. Quoting `input` and `output` is not an adequate defense because embedded quotation marks and shell metacharacters are neither rejected nor safely escaped. ### Attack Path 1. An attacker influences the arguments supplied to `scripts/rotate.js`, directly or through an Agent-generated invocation. 2. The attacker places shell syntax in `--angle`, `--scale`, `--input`, or `--output`. 3. `parseArgs` stores the value without validation. 4. The value is concatenated into `cmd`. 5. `execSync` passes the constructed string to the operating-system shell. 6. The shell interprets the injected syntax and executes an additional command with the privileges of the Node.js pr ...[truncated 524 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Avoid invoking a shell. Use `execFileSync` or `spawnSync` with a fixed executable and an argument array: ```js const { execFileSync } = require('child_process'); const parsedAngle = Number(angle); const parsedScale = Number(scale); if (!Number.isFinite(parsedAngle)) { throw new Error('Angle must be a finite number'); } if (!Number.isFinite(parsedScale) || parsedScale <= 0) { throw new Error('Scale must be a positive finite number'); } const result = execFileSync( 'cli-anything-imutils', [ 'rotate-cmd', input, output, '--angle', String(parsedAngle), '--scale', String(parsedScale) ], { encoding: 'utf-8', shell: false } ); ``` Additional hardening should include: - Validate `input` before deriving the default output path. - Reject missing option values and unexpected arguments. - Apply reasonable numeric ranges to angle and scale. - Verify that input and output paths comply with the intended filesystem policy. - Run image-processing operations with the minimum required operating-system permissions. - Add tests using spaces, quotation marks, and shell metacharacters to confirm that arguments are handled only as data. ]]>
