T09 · Insecure Skill Coding Practices
- Location
scripts/voice-processor.js:34- Finding
Shell Command Injection Through Unsafe Audio Path Interpolation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/voice-processor.js, lines 34-42
Vulnerability Type: OS command injection
Risk Level: HighVulnerable code:
javascript async function transcribeVoiceNote(audioFilePath) { try { const scriptDir = path.dirname(__filename); const transcribeScript = path.join(scriptDir, 'transcribe.py'); const { stdout, stderr } = require('child_process').execSync( `python "${transcribeScript}" "${audioFilePath}"`, { maxBuffer: 10 * 1024 * 1024, encoding: 'utf8' } );Technical Analysis
audioFilePathis interpolated directly into a command string passed toexecSync. By default,execSyncprocesses a string through a system shell. Quoting the path does not make it safe because a path containing a double quote followed by shell metacharacters can terminate the quoted argument and append another command.The vulnerable
transcribeVoiceNotefunction is exported as part of the public module API and is documented as accepting a caller-provided file path. Therefore, any integration that passes an untrusted or insufficiently validated path to this function creates a command-execution primitive.The code also incorrectly destructures the return value of
execSync: withencoding: 'utf8', the method returns a string rather than an object containingstdoutandstderr. This causes normal transcription to fail whenstdout.matchis subsequently called. It does not prevent the injected shell command from running, because command execution occurs before the return value is processed.Attack Path
- An attacker reaches an integration that exposes
transcribeVoiceNoteor otherwise controls the supplied audio path. - The attacker submits a path containing a closing quote and shell syntax, such as a path conceptually structured as
" ; attacker-command ; ". - The application embeds that value into the command string with ...[truncated 743 chars]
- An attacker reaches an integration that exposes
- Remediation
View remediation
Remediation Suggestions
Replace shell-based execution with
execFileorspawnand pass arguments as an array with shell processing disabled:javascript const { execFile } = require('child_process'); const { promisify } = require('util'); const execFileAsync = promisify(execFile); async function transcribeVoiceNote(audioFilePath) { const scriptDir = path.dirname(__filename); const transcribeScript = path.join(scriptDir, 'transcribe.py'); const { stdout } = await execFileAsync( 'python3', [transcribeScript, audioFilePath], { shell: false, maxBuffer: 10 * 1024 * 1024, encoding: 'utf8' } ); // Parse stdout here. }Additionally:
- Resolve and validate the path before use.
- Restrict accepted paths to an explicitly permitted directory where appropriate.
- Reject unexpected file types and non-regular files.
- Run the process under a dedicated, least-privileged account.
- Add regression tests using paths containing quotes, spaces, command separators, and substitution syntax.
