T09 · Insecure Skill Coding Practices
Error
- Location
- src/scripts/progress-report.js:9
- Finding
- Shell Command Injection Through Repository Name in Progress Report## Vulnerability Details **File Location**: `src/scripts/progress-report.js:9-13` **Vulnerability Type**: OS command injection through shell interpolation **Risk Level**: High ### Vulnerable Code ```javascript function generateProgressReport(repoName) { try { const issues = execSync(`gh issue list --repo ${repoName} --limit 50`, { encoding: 'utf8' }); const commits = execSync(`gh pr list --repo ${repoName} --limit 20`, { encoding: 'utf8' }); ``` ### Technical Analysis The exported `generateProgressReport` function places `repoName` directly into command strings passed to `child_process.execSync`. This API invokes a shell, so shell metacharacters in the repository name are interpreted as command syntax rather than as part of a single GitHub CLI argument. There is no validation that the value has the expected `owner/repository` format and no escaping or argument separation. Any application component that invokes this exported function with user-controlled repository data can consequently provide additional shell commands. ### Attack Path 1. An attacker supplies a repository name through an integration, API, agent task, or other caller of `generateProgressReport`. 2. The value contains shell syntax, for example: ```text valid/repo; touch /tmp/progress-report-injection; # ``` 3. The function constructs a command equivalent to: ```sh gh issue list --repo valid/repo; touch /tmp/progress-report-injection; # --limit 50 ``` 4. `execSync` executes both the intended GitHub CLI invocation and the injected command. 5. More consequential payloads could read application credentials, alter files, execute downloaded programs, or invoke other tools available to the Node.js process. ### Impact Assessment Successful exploitation provides arbitrary command execution with the operating-system privileges of the Node.js process. The attacker can access files and environment variables availa ...[truncated 378 chars]
- Remediation
- ## Remediation Suggestions - Replace shell-based `execSync` with `execFileSync` or `spawnSync` and pass every argument separately: ```javascript const { execFileSync } = require('child_process'); function validateRepository(repoName) { if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repoName)) { throw new Error('Invalid GitHub repository identifier'); } return repoName; } const repository = validateRepository(repoName); const issues = execFileSync( 'gh', ['issue', 'list', '--repo', repository, '--limit', '50'], { encoding: 'utf8', shell: false } ); ``` - Apply a strict allowlist for GitHub owner and repository syntax and enforce a reasonable maximum length. - Do not attempt to solve this solely by adding quotes; argument-array execution with `shell: false` is safer. - Run the process under a dedicated, minimally privileged account. - Restrict GitHub tokens to the minimum repository and operation scopes. - Add regression tests containing semicolons, command substitutions, quotes, newlines, pipes, and redirection characters, verifying that all are rejected or treated as literal data.
