T09 · Insecure Skill Coding Practices
- Location
introspection-debugger.js:167- Finding
Shell Command Injection Through Automatic Dependency Installation
- Content
View full analysis
{ const moduleName = this.extractModuleName(error.message); if (moduleName) { try { await this.execAsync(`npm install ${moduleName}`, { cwd: this.workspace }); return { action: 'installed_dependency', module: moduleName }; } catch (e) { return { action: 'install_failed', module: moduleName, reason: e.message }; } } return null; }, ``` The constructed command is passed to a shell: ```javascript execAsync(cmd, options = {}) { return new Promise((resolve, reject) => { exec(cmd, options, (error, stdout, stderr) => { if (error) reject(error); else resolve(stdout); }); }); } ``` ### Technical Analysis The module name is extracted from an error message and interpolated directly into a shell command. The extraction logic does not enforce valid npm package syntax and does not reject shell metacharacters. Because `child_process.exec()` invokes a shell, control operators, command substitutions, redirections, or other shell syntax embedded in the extracted value can alter the intended command. The automatic error-capture design makes this particularly dangerous because a crafted error can trigger command execution without a separate authorization step. ### Attack Path 1. An attacker causes the application to capture an error whose message matches `MODULE_NOT_FOUND` or `Cannot find module`. 2. The crafted message contains shell syntax in the text parsed by `extractModuleName()`. 3. Root-cause analysis selects the `installDependency` repair method. 4. The extracted value is interpolated into `npm install ${moduleName}`. 5. `exec()` passes the resulting string to the operating-system shell. 6. The injected command executes with the p ...[truncated 418 chars]- Remediation
View remediation
