How I Detected and Stopped a Real-World RCE Attack on My Next.js App (CVE-2025-55182 / React2Shell)

Published: (December 12, 2025 at 08:00 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

Cover image for How I Detected and Stopped a Real-World RCE Attack on My Next.js App (CVE-2025-55182 / React2Shell)

Last week I experienced one of the most eye‑opening security incidents in my time building web apps.
My production Next.js application was actively targeted by attackers attempting remote code execution (RCE), and the root cause was a newly disclosed vulnerability in React Server Components.

The write‑up covers what happened, how I diagnosed the issue, how I patched it, and the steps I took to harden my infrastructure.

1) The First Signs: Suspicious Logs in My Container

Everything began when I noticed strange logs while checking my Docker containers:

/bin/sh: curl: not found
/base64 -d | bash
ping: bad address
cat: can't open '.env.production'

Attackers were:

  • Attempting to download malicious scripts
  • Trying to exfiltrate environment variables
  • Dropping files into /tmp
  • Running reconnaissance commands
  • Injecting base64‑encoded payloads

At this stage, nothing persisted on the filesystem, and no malicious binaries survived container restarts—a good sign, but it was clear something was trying to execute shell commands inside my app.

2) Investigating the Root Cause

My first instinct was to examine my own server‑side code:

  • Reviewed all route handlers
  • Audited every Server Action
  • Scanned the codebase for any child_process.exec, spawn, or CLI wrappers

None of my code executed shell commands, so I turned to the next logical suspicion: a framework‑level vulnerability.

The Culprit: CVE‑2025‑55182 (React2Shell)

My app was running a Next.js version that used a vulnerable build of React Server Components, specifically the versions affected by CVE‑2025‑55182 – React2Shell.

The vulnerability is a pre‑authentication RCE caused by unsafe deserialization in React’s RSC/Flight protocol. With a single crafted HTTP request, an attacker could trigger arbitrary code execution inside the Node.js server, even without custom API endpoints.

I tested the publicly available PoC against my running app… and it worked. Suddenly everything made sense.

3) Fixing the Vulnerability

The React team released patches, and Next.js provided an official tool to upgrade vulnerable packages.

npx fix-react2shell-next

Running the command updated:

  • React RSC internals
  • Next.js internals that depend on the vulnerable code path

I rebuilt and redeployed the app from clean Docker images. Then I tested the PoC again: Exploit failed. Completely. The issue was resolved.

Successful patch

Running npx fix-react2shell-next on an affected Next.js app – confirming active vulnerabilities and applying the official patch.

4) Hardening My Infrastructure (This Saved Me)

Even though the vulnerability existed, the attacker never gained persistence or escalated to the host. The reason was the hardened Docker environment:

  • Read‑only root filesystem
  • /tmp mounted with noexec
  • All Linux capabilities dropped
  • no-new-privileges enabled
  • No bash or curl installed inside the container
  • Isolated writable directories
  • Nginx rate limiting and reverse‑proxy filtering

These layers prevented file execution, script downloads, persistence installation, cron modifications, privilege escalation, and writing outside isolated volumes. In the end, the vulnerability allowed RCE, but the environment stopped it from becoming a full compromise.

5) Post‑Incident Actions

After patching, I also:

  • Rotated all environment secrets
  • Redeployed everything from clean images
  • Validated that no malicious files remained
  • Reviewed logs to confirm attack attempts were blocked

Because, as we often say, security is not just about fixing one issue; it’s an ongoing process.

6) Key Takeaways for Developers

  • Patch fast – React2Shell was actively exploited in the wild. If your app uses Next.js + RSC, update immediately.
  • Least privilege saves lives – A read‑only root filesystem alone can break ~80 % of real‑world attack chains.
  • Don’t rely on your own code being perfect – Framework vulnerabilities happen; attackers move fast.
  • Use multiple layers of defense – No single measure stopped this attack; together they did.
  • Monitor everything – Logs revealed the attack before it was too late.

7) The Bottom Line

This experience was intense but deeply educational. Incidents like this can happen to anyone, and every victim has their own story behind it. It reinforced how important it is to stay up to date, harden your runtime environment, assume that vulnerabilities will happen, and prepare your infrastructure to handle them safely.

If even one person reading this patches their application or improves their security setup, then writing this was absolutely worth it.

References

Back to Blog

Related posts

Read more »