T09 · Insecure Skill Coding Practices
- Location
scripts/backup.mjs:604- Finding
Command Injection Through the User-Controlled Backup Output Path
- Content
View full analysis
a.startsWith('--exclude=')) const excludeIds = excludeArg ? excludeArg.replace('--exclude=', '').split(',') : [] const outputDir = args.find(a => !a.startsWith('--')) || join(homedir(), 'Desktop', `cc-backup-${DATE}`) backup(outputDir, excludeIds) } ``` The user-controlled value subsequently reaches shell commands during archive creation: ```js if (platform() === 'win32') { const zipName = `${dirName}.zip` execSync( `powershell -Command "Compress-Archive -Path '${outputDir}' -DestinationPath '${join(parentDir, zipName)}'"`, { stdio: 'pipe' } ) info(`Backup archive: ${join(parentDir, zipName)}`) } else { const archiveName = `${dirName}.tar.gz` execSync(`tar -czf "${join(parentDir, archiveName)}" -C "${parentDir}" "${dirName}"`, { stdio: 'pipe' }) info(`Backup archive: ${join(parentDir, archiveName)}`) } ``` ### Technical Analysis The first positional command-line argument is accepted as `outputDir` without restrictions. Components derived from this value are interpolated into command strings passed to `execSync`. Unlike direct process execution with an argument array, `execSync` parses the assembled string through a command shell. Quotation marks alone are not a sufficient defense: a malicious path containing shell-specific quotation characters, substitutions, separators, or other metacharacters can terminate the intended argument and introduce an additional command. Both supported archive branches are affected: - On Unix-like systems, `outputDir`, `parentDir`, and `dirName` influence the `tar` command string. - On Windows, `outputDir` and the archive destination are embedded inside a PowerShell co ...[truncated 1521 chars]- Remediation
View remediation
