Back to Field Notes
Incident Recovery & Security•September 18, 2025•8 min read

Surviving a Zero-Day React2Shell Attack: How We Recovered Root & 100% CPU Under Peak Live Traffic

Out-of-band VNC rescue, terminating masked cryptominers, scrubbing persistent cronhooks, and containerizing production services with zero database loss.

By Abdullah Al Mamun • Systems Architect & Founder
Title card for the React2Shell incident post-mortem — recovering a 100% CPU Linux VPS after the CVE-2025-55182 zero-day exploit

A forensic engineering breakdown of how an unpatched zero-day vulnerability in an upstream web framework allowed an unauthorized actor to deploy a persistent cryptominer, driving CPU and RAM to 100% on our co-located production host. Here is how we regained root control via out-of-band VNC, eradicated malware persistence, and restored full uptime with zero data loss in under 45 minutes.

Table of Contents (6 sections)▼

1. The Incident: Complete Resource Starvation at 100% CPU

Under standard operational conditions, our production multi-core Linux host runs at a stable 15–20% CPU utilization and ~30% RAM utilization. This server concurrently powered the live LMS video delivery for Pro Trainer IT students while handling continuous subscription transactions on SubsDrop.

At approximately 03:40 AM, automated health check probes reported 504 Gateway Timeouts. Within two minutes, SSH daemon connection attempts began hanging with TCP reset timeouts. Out-of-band hypervisor metrics showed all 8 vCPUs pinned at 100.0%, RAM pegged at 99%, and disk I/O throughput maxed out.

Dozens of customer tickets poured in: students couldn't access ongoing cohorts and buyers were stuck on payment verification. The host operating system was completely suffocating.

Critical Telemetry Alert

Host: prod-node-alpha (Ubuntu 24.04 LTS) | CPU Load Average: 42.18, 38.12, 29.40 | Inbound/Outbound: Unsolicited mining pool socket traffic detected on ports 3333 and 14444.

2. Out-of-Band VNC Rescue & Process Inspection

Because standard SSH connection handshakes were denied by process thread pool starvation, I opened a low-level out-of-band VNC emergency console provided by our cloud hypervisor. This accessed the TTY console directly without needing network socket allocation.

Executing 'top' showed multiple worker processes disguised as legitimate Linux kernel threads like '[kworker/u16:3]' and '[systemd-journald-helper]', each consuming 99.8% CPU.

Inspecting '/proc/<pid>/exe' revealed that these processes were actually executing compiled XMRig binaries hidden under '/tmp/.sysd' and '/dev/shm/.cache'.

forensics_triage.sh
# Step 1: Freeze rogue process tree immediately
kill -STOP 41922 41923

# Step 2: Uncover real binary path and working directory
ls -l /proc/41922/exe
# Output: /proc/41922/exe -> /tmp/.sysd/.xmrig (deleted)

ls -l /proc/41922/cwd
# Output: /proc/41922/cwd -> /dev/shm/.cache

# Step 3: Analyze outbound mining sockets
ss -tunap | grep -E "3333|14444|pool"
# tcp SYN_SENT 10.0.1.4:48122 -> 198.51.100.22:3333 (users:(("kworker",pid=41922,fd=3)))
Key Takeaway

Never simply 'kill -9' an unknown rogue process immediately without running 'kill -STOP' first to freeze its execution state, inspect '/proc/<pid>/', and identify its parent PID or cron respawner.

3. Root Cause Analysis: CVE-2025-55182 Exploitation

Parsing Nginx reverse-proxy access logs and Node.js process logs revealed an unauthenticated POST request containing serialized JSON payloads aimed at an upstream React SSR handler.

This matched the signature for CVE-2025-55182 (dubbed React2Shell), where improper deserialization of component server actions permitted arbitrary command injection. The attacker injected a base64-encoded curl script that downloaded a payload into '/tmp', executed it, and immediately deleted the source file on disk to evade basic signature scanners.

4. Scrubbing Malware Persistence (Cron, Sockets, Immutable Flags)

Modern cryptominers drop multiple layers of stealth persistence so that if you terminate the process, it resurrects automatically within minutes. We methodically scrubbed every persistence hook:

1. Checked and cleaned root and www-data crontabs, '/etc/crontab', and '/etc/cron.d/'. Found a stealth entry triggering a base64 curl command every 5 minutes.

2. Inspected '/etc/systemd/system/' for unauthorized timer units.

3. Checked '/root/.ssh/authorized_keys' and verified no foreign public keys had been appended.

4. Removed immutable flags (chattr -i) on files under '/tmp' and completely emptied rogue directories.

purge_persistence.sh
# Remove immutable attributes if malware locked files
chattr -i -a /tmp/.sysd/* 2>/dev/null
rm -rf /tmp/.sysd /dev/shm/.cache

# Clean all cron directories
rm -f /etc/cron.d/sync-system-time
sed -i '/pastebin\|curl\|wget/d' /var/spool/cron/crontabs/* 2>/dev/null

# Terminate rogue processes permanently
pkill -9 -f "xmrig"
pkill -9 -f ".sysd"

# Flush DNS cache and block mining pool IPs at kernel level
sudo ufw deny out to 198.51.100.0/24 comment "Rogue Mining Pool Subnet"

5. Architectural Hardening & Container Resource Capping

Recovering root access was only half the battle. To ensure such an incident could never bring down both platforms again, we executed a structural re-architecture:

1. Container Decoupling: We isolated SubsDrop and Pro Trainer IT into independent Docker containers with strict 'cpu_quota' limits. No single service can ever consume more than 250% CPU or 4GB RAM.

2. Filesystem Mount Hardening: Mounted '/tmp' and '/dev/shm' with 'noexec,nosuid,nodev' options in '/etc/fstab'. Even if an RCE downloads a binary into '/tmp', Linux kernel refuses to execute it.

3. Private Database VPC Isolation: Verified MongoDB is bound strictly to internal private IP with zero 0.0.0.0 binding.

docker-compose.hardened.yml
services:
  subsdrop-api:
    image: subsdrop/core:latest
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: "2.50"      # Hard ceiling: max 2.5 vCPUs
          memory: 3500M     # Hard ceiling: max 3.5GB RAM
        reservations:
          cpus: "0.50"
          memory: 1024M
    read_only: true         # Root filesystem is read-only
    tmpfs:
      - /tmp:noexec,nosuid,size=128m
    security_opt:
      - no-new-privileges:true
    networks:
      - internal_vpc

networks:
  internal_vpc:
    internal: true

6. Production Checklist & Post-Mortem Lessons

The host was fully restored to service in under 45 minutes with 0 bytes of customer data lost. Post-patch CPU immediately dropped back to a baseline of 14%.

Lessons cemented into our team's Standard Operating Procedure (SOP):

• Never co-locate multi-tenant apps on raw bare-metal or single PM2 instances without container resource boundaries.

• Always mount '/tmp' as 'noexec'. This blocks 90% of automated zero-day malware drops from running.

• Keep out-of-band VNC console access verified and ready before emergencies occur.

Production Implementation

Review the verified telemetry in the React2Shell Incident Post-Mortem.

Frequently Asked Questions

What is React2Shell CVE-2025-55182?
React2Shell (CVE-2025-55182) is a critical zero-day remote code execution vulnerability in certain React SSR frameworks that allowed attackers to execute arbitrary shell commands on the host server, typically deploying persistent cryptominers that consume 100% CPU.
How do I check for cryptominer persistence on Linux?
Check crontabs (crontab -l and /var/spool/cron/), systemd timers (systemctl list-timers), /etc/rc.local, and inspect running processes with top or htop for disguised binaries. Also check for immutable file attributes using lsattr on suspicious files in /tmp and /var/tmp.
Does Docker CPU limiting prevent cryptominer damage?
Docker CPU limits (--cpus flag or deploy.resources.limits in Compose) contain cryptominer impact by capping the container's CPU share. While it won't prevent infection, it ensures the miner cannot starve the host OS and other containers, buying time for detection and remediation.
Tags:#CVE-2025-55182#Linux Hardening#Malware Containment#Incident Response#Docker#DevOps
Abdullah Al Mamun

Systems Architect & Founder of SubsDrop, QuickMation, and MoneTrix.

Discuss Systems