DEV Community

Cover image for How Avoiding Next.js Turned Into a 9.8 CVE-Level Security Nightmare
Tofiq Hamzaie
Tofiq Hamzaie

Posted on

How Avoiding Next.js Turned Into a 9.8 CVE-Level Security Nightmare

I'm Scared

Do you know what’s scarier than an RSC vulnerability with a CVE score of 10?
Trying to roll your own SSR system for a React app… using a Node.js server stitched together with hope, vibes, and absolutely no security hardening.

Yeah. That kind of nightmare.

Background Story

I met a friend today and casually brought up the recent React Server Components security issue. I told him it was serious issue, the kind of issue that gets security researchers out of bed in the morning. I suggested he update the relevant RSC libraries in his app, the one where he implemented SSR manually.

He waved it off instantly.

“That’s a Next.js problem. My app isn’t built on Next.js.”

I explained that the vulnerability was in RSC itself, not in Next.js, which only inherited it. But again, he insisted:

“I’m not even using RSC.”

At that point, curiosity took over. If he wasn’t using RSC, then what exactly was powering his SSR?

He opened the project. And when I saw the server code, a cold breeze passed through me. My only reaction was:

“Bro… did you vibe-code your entire SSR engine?”

I'm Shocked (And So Was He)

Let me paint a picture of what I found — without exposing a single line of his code. Note all of this is on one file.

  1. The entire domain logic and routing layer manipulated the Host header directly

The server trusted whatever “Host” value the client sent. It rewrote URLs, enforced redirects, and rebuilt full HTTPS URLs using unchecked input from the request.
This alone opens the door to open redirects, phishing vectors, and host header attacks.

  1. The server accepted arbitrarily large request bodies

No size limits, No rate limits, No timeout controls, Nothing.

A single malicious request could exhaust memory or spawn infinite processes.
That’s how you get Denial of Service via unbounded request bodies.

  1. The biggest bomb: Node.js was literally executing PHP scripts directly based on incoming requests

Not only that, it forwarded user input straight into a PHP process.
The server opened a child process for each request, piped the client’s body into it, and returned whatever the PHP script printed.

No sanitization, No validation, No constraints, No concurrency limits, No sandboxing.

This is the kind of setup that can:

  • Expose environment variables
  • Leak internal state
  • Exhaust server resources
  • Execute unintended code paths
  • Trigger chain-vulnerabilities between Node and PHP

A perfect breeding ground for DoS, environment leaks, XSS, and arbitrary remote actions.

  1. The server trusted proxies blindly

It enabled “trust proxy” without configuring safe IP ranges.
That means a random attacker could spoof certain headers and influence behavior intended only for internal load balancers.

  1. SSR rendering inserted unescaped data back into the HTML

State hydration values were directly injected into the HTML template without HTML escaping.
If any user-controlled content made it into the SSR context, that instantly becomes full-blown XSS, capable of stealing sessions or performing privileged actions.


My friend looked at me, then at the vulnerability list generated by the AI, I watched the exact moment he realized this could have gone catastrophically wrong.

He genuinely didn’t know these were real, severe security issues.
He thought he was simply “rendering PHP from Node” because it worked.

Sometimes the most dangerous bugs are the ones that feel harmless.

CVE Rating: 9.8?!

For fun, I asked Gemini what CVE score it would assign if this code were a real-world vulnerability.

It answered: 9.8

To be fair, I asked Gemini to review the code in the most pessimistic, worst-case-scenario way possible. Some findings might not apply exactly as listed.

But security is one domain where pessimism is actually a job requirement.
Especially when you're writing a custom SSR system from scratch.

Summary

Frameworks have vulnerabilities sure. But they also come with teams of engineers and a community patching, testing, and auditing the security model you're standing on.

When you vibe-code your own SSR engine, You become the security team.

And unless you're prepared to test every header, every body size limit, every escape mechanism, every child process, every redirect rule…

You’re one mistake away from writing your own CVE.

Top comments (0)