T09 · Insecure Skill Coding Practices
Error
- Location
- src/index.js:30
- Finding
- OS Command Injection in the Primary Google Drive Implementation<![CDATA[ ## Vulnerability Details **File Location**: `src/index.js:30-31, 61-71, 106-108, 137-148, 179-181` **Vulnerability Type**: OS command injection through shell command construction **Risk Level**: High ### Vulnerable Code ```js const command = `gog drive files upload --account ${account} --file "${filePath}" --name "${fileName}" --parents "${folder}" --mime-type "${mimeType}" --json`; const { stdout } = await execAsync(command, { shell: true }); ``` ```js let command = `gog drive files list --account ${account} --max ${limit} --json`; if (folder !== 'root') { command += ` --parents "${folder}"`; } if (query) { command += ` --query "name contains '${query}'"`; } const { stdout } = await execAsync(command, { shell: true }); ``` ```js const command = `gog drive files list --account ${account} --max ${limit} --query "${searchQuery}" --json`; const { stdout } = await execAsync(command, { shell: true }); ``` ```js const infoCommand = `gog drive files get --account ${account} --file ${fileId} --json`; const { stdout: infoStdout } = await execAsync(infoCommand, { shell: true }); const fileInfo = JSON.parse(infoStdout); const fileName = fileInfo.name; const destination = path.join(outputPath, fileName); const downloadCommand = `gog drive files download --account ${account} --file ${fileId} --output "${destination}"`; await execAsync(downloadCommand, { shell: true }); ``` ```js const command = `gog drive permissions create --account ${account} --file ${fileId} --role ${role} --type user --email-address "${email}" --json`; const { stdout } = await execAsync(command, { shell: true }); ``` ### Technical Analysis The implementation creates command strings by directly interpolating caller-controlled or remotely derived values and then passes those strings to `child_process.exec` with shell processing enabled. Affected values include: - `account` - `filePath` - `customName` or the derived filename - `folder` - `limit` - `query` - `fileType` - `fileId ...[truncated 1993 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace `exec` with `execFile` or `spawn` and pass arguments as an array. Do not enable shell processing. ```js import { execFile } from 'child_process'; import { promisify } from 'util'; const execFileAsync = promisify(execFile); const { stdout } = await execFileAsync('gog', [ 'drive', 'files', 'list', '--account', account, '--max', String(limit), '--query', searchQuery, '--json' ]); ``` 2. Apply strict validation in addition to argument separation: - Require `limit` to be a bounded positive integer. - Allow only supported sharing roles such as `reader`, `writer`, and `commenter`. - Validate email addresses and Google Drive IDs. - Validate account identifiers using an appropriate allowlist. - Reject null bytes and unexpected control characters in paths and names. 3. Treat Google Drive metadata, including filenames, as untrusted input. 4. Centralize all `gog` invocations in one shell-free helper to prevent future regressions. 5. Add automated tests containing spaces, quotes, semicolons, backticks, and `$()` expressions, confirming that they remain literal arguments and never execute. ]]>
