T09 · Insecure Skill Coding Practices
- Location
index.js:42- Finding
OS Command Injection in Text-to-Speech Command Construction
- Content
View full analysis
Vulnerability Details
File Location:
index.js, lines 42-49
Vulnerability Type: OS command injection through shell interpolation
Risk Level: CriticalVulnerable Code
javascript // 1. 清洗文本格式,避免朗读出标记符号 const cleanedText = cleanTextForTTS(text); console.log(`清洗后的文本: ${cleanedText.substring(0, 50)}...`); // 2. 使用 edge-tts 生成语音 console.log(`正在生成语音: ${cleanedText.substring(0, 50)}...`); await execAsync(`edge-tts --voice "${voice}" --rate="${rate}" --text "${cleanedText.replace(/"/g, '')}" --write-media "${tempMp3}"`);Technical Analysis
The function constructs a shell command by directly interpolating the caller-controlled
text,voice, andratevalues.child_process.execexecutes the resulting string through a system shell.Removing double-quote characters from
cleanedTextis not adequate shell escaping. Shell command substitutions such as$(...)and backtick substitutions are evaluated even when they occur inside double quotes. Thevoiceandrateparameters are not sanitized at all and can also contain quote-breaking shell syntax.Text cleanup is designed for speech formatting and is not a security boundary. It does not prevent shell metacharacters or command substitution.
Attack Path
- An attacker reaches a workflow that invokes
sendVoiceToTelegramGroup. - The attacker supplies malicious
text,voice, orrateinput. For example, the text can contain a shell command substitution expression. - The input is interpolated into the command passed to
execAsync. - The operating-system shell evaluates the injected syntax before or while invoking
edge-tts. - The injected command executes with the privileges and environment of the OpenClaw/Node.js process.
Impact Assessment
Successful exploitation permits arbitrary operating-system command execution under the service account. Depending on that account's privileges, an attacker could read or modify a ...[truncated 382 chars]
- An attacker reaches a workflow that invokes
- Remediation
View remediation
Remediation Suggestions
- Replace
child_process.execwithexecFileorspawnand pass each argument as a separate array element. - Do not invoke a shell for either Edge TTS or FFmpeg.
- Apply an allowlist of supported voice identifiers.
- Validate
rateagainst a narrow expression such as^[+-](100|[0-9]{1,2})%$, adjusted to the actual supported range. - Impose text length and character limits appropriate to the TTS service.
- Do not rely on Markdown cleanup as command-injection protection.
- Run media conversion in a restricted service account or sandbox with minimal file and network access.
Example hardened invocation:
javascript const { execFile } = require('child_process'); const execFileAsync = util.promisify(execFile); await execFileAsync('edge-tts', [ '--voice', voice, '--rate', rate, '--text', cleanedText, '--write-media', tempMp3 ], { shell: false, timeout: 120000, maxBuffer: 1024 * 1024 });- Replace
