How a React CVE Broke My Sense of Safety (and What I did About It)
Author
Md Arshad Khan
Date Published

It started with a sluggish dashboard. My Next.js portfolio, usually snappy, was timing out. I logged into my VPS to restart the service and saw the one thing every dev dreads: CPU usage at 100%.
A process named kworkerds (a common disguise for miners) was chewing up every core. I killed the process. It came back. I deleted the binary. It came back. I thought I had fixed it, but 12 hours later, my hosting provider sent a “Violation of Terms” email for high-CPU usage.
I had been hit by a React Server Components RCE (Remote Code Execution) vulnerability. But the real problem wasn’t just the CVE , it was that I had deployed my app as root.
This is the story of how I was humbled, hacked again, and finally forced to learn Linux security the hard way.
The Initial Breach: Why “sudo” Matters
The vulnerability (let’s call it the “React2Shell” CVE) allowed an attacker to send a malicious payload to my server-rendered component. Because my app ran as root , the attacker didn’t just crash the app , they became the server admin instantly.
They used this access to download a cryptominer and set up “persistence” , hidden scripts that ensure the malware restarts if you try to kill it.
The “Twice” Part: Why Killing the Process Failed
After the first infection, I simply ran kill -9 <pid> and deleted the suspicious files I could find. I thought I was clever.
I wasn’t.
The attacker had added a cron job (a scheduled task) that re-downloaded the miner every minute. They also added a systemd service file disguised as a legitimate system process. By missing these persistence mechanisms, I left the back door wide open. The second infection wasn’t a new attack; it was the old one resurrecting itself because I hadn’t cleaned the infection at the root.
The Nuclear Option: Scorched Earth Policy
I realized I couldn’t trust the OS anymore. There could be hidden SSH keys, modified binaries, or other backdoors I couldn’t see.
I did the only safe thing: I destroyed the VPS and reinstalled the OS from scratch.
Then, I rebuilt it with a “security-first” mindset. Here is the exact configuration I used to prevent this from ever happening again.
Step 1: The Non-Root User (The Golden Rule)
Never, ever run your production apps as root. If my app had been running as a limited user, the RCE would have only crashed the app, not compromised the entire kernel.
1adduser deployer2usermod -aG sudo deployer
Now, I log in as deployer . If I need to install something, I type password for sudo. If my app gets hacked, the attacker is trapped in the deployer user’s limited sandbox.
Step 2: Banning Root SSH Login
Attackers love the root user because the username is always known. I cut off this entry point entirely.
1PermitRootLogin no2PasswordAuthentication no
I switched to SSH Key Authentication only. Now, even if an attacker guesses my password, they can’t log in without my physical laptop’s private key. The server simply ignores password attempts.
Step 3: Fail2Ban (The Bouncer)
Even with keys, bots were still spamming my SSH port, filling up logs. Fail2Ban monitors these logs and bans IPs that show malicious behavior.
1sudo apt install fail2ban
1[sshd]2enabled = true3port = ssh4filter = sshd5logpath = /var/log/auth.log6maxretry = 37bantime = 1h
Now, after 3 failed tries, the attacker’s IP is blocked by the firewall for an hour.
Step 4: UFW (The Firewall)
I used UFW (Uncomplicated Firewall) to ensure only the absolute necessary doors were open.
This ensures that even if I accidentally start a database service on a public port, the firewall blocks outside access to it by default.
1sudo ufw default deny incoming2sudo ufw allow ssh3sudo ufw allow http4sudo ufw allow https5sudo ufw enable
The Outcome
Since rebuilding with this setup:
1. CPU usage is a flat line (except when I deploy!).
2. Logs show thousands of blocked attempts by Fail2Ban each one a bullet dodged.
3. Peace of mind: Knowing that even if a new React CVE drops tomorrow, the attacker can’t easily install a rootkit.
Lesson Learned: Security isn’t a “feature” you add later. It’s the foundation. If you’re deploying a VPS today, create that non-root user before you install Node.js.