T09 · Insecure Skill Coding Practices
- Location
scripts/create_word_with_superscript.js:334- Finding
OS Command Injection in Automatic Document Opening
- Content
View full analysis
Vulnerability Details
File Location:
scripts/create_word_with_superscript.js, lines 334-346
Vulnerability Type: OS command injection through an untrusted file path
Risk Level: HighVulnerable Code
javascript // Automatically open the document const { exec } = require('child_process'); const platform = process.platform; let command; if (platform === 'win32') { command = `start "" "${outputPath}"`; } else if (platform === 'darwin') { command = `open "${outputPath}"`; } else { command = `xdg-open "${outputPath}"`; } exec(command, (error) => {The vulnerable
outputPathvalue is derived from command-line input earlier in the file:javascript const inputFile = process.argv[2] || 'your_review.md'; const outputFile = inputFile.replace('.md', '_上标版.docx'); const outputPath = path.resolve(outputFile);Technical Analysis
The script accepts a user-controlled Markdown path through
process.argv[2]. It derivesoutputPathfrom that path and interpolates the result into a command string passed tochild_process.exec().exec()runs the command through an operating-system shell. Although the path is enclosed in double quotes, quoting does not safely escape embedded quote characters or shell metacharacters. A maliciously constructed filename can terminate the quoted argument and append an additional shell command.The issue affects the automatic-open operation on Windows, macOS, and Linux because each platform branch builds a shell command through string interpolation. The generated document does not need to contain malicious document content; the attack is carried by its filesystem path.
Attack Path
- An attacker creates a Markdown file whose filename contains shell-significant characters suitable for the victim’s operating system.
- The attacker supplies the file to a user or persuades the user to process it with:
bash node scripts/create_word_with_superscript.js <crafted-file-path> - The sc ...[truncated 1275 chars]
- Remediation
View remediation
Remediation Suggestions
Replace shell-based string execution with an argument-array process API that does not invoke a shell:
javascript const { spawn } = require('child_process'); let opener; let args; if (platform === 'win32') { opener = 'explorer.exe'; args = [outputPath]; } else if (platform === 'darwin') { opener = 'open'; args = [outputPath]; } else { opener = 'xdg-open'; args = [outputPath]; } const child = spawn(opener, args, { shell: false, detached: true, stdio: 'ignore' }); child.on('error', () => { console.log('Automatic opening failed; open the document manually.'); }); child.unref();Additional hardening measures:
- Make automatic document opening opt-in rather than enabled by default.
- Add a
--no-auto-openoption consistent with the Python checker. - Validate that the generated path refers to the expected
.docxoutput before launching it. - Avoid attempting to secure
exec()through manual quoting or character replacement; platform-specific shell parsing makes this error-prone. - Add regression tests using paths containing spaces, quotes, command separators, substitution syntax, and Unicode characters.
- Document that input paths are untrusted and must never be inserted into shell command strings.
