For: anyone shipping apps with Next.js (or similar JS frameworks), especially "built it with AI's help, operating by feel." Distilled from a real incident (→ the neglected CVSS 10.0).
This site's view: what matters is not speed but a system that doesn't miss
When indie developers fall short at security, it is usually not from lack of knowledge but because they can't keep operations going. Reading CVE news faster than anyone has no value (leave speed to vendors and news). What works is a system that won't miss the CVEs relevant to you. So this article focuses on building that system rather than on knowing more.
1. Judge by the running version
Measure "am I on a dangerous version" by what's actually running, not the manifest floor — because the manifest number and the running version often disagree.
✗ Count by the package.json floor
"next": "^16.0.0" → "16.0.0 is vulnerable, so we are" — over-counted as "8 vulnerable".
✓ Count by the running version
npm ls next shows the resolved version → auto-bumped ones are safe, only pinned ones lag. Really 2.
# see the versions actually resolved
npm ls next react react-dom
# inside a running container
docker exec <container> npm ls nextCaret ranges (^16.0.0) auto-bump on rebuild; pinned deps lag. Judge by the versions shown here.
How to check your own setup
These steps tell you which version your app is actually running and whether a known CVE applies. Each one only inspects your own environment.
Check the local version
Run npx next info in the project folder. It shows the actual versions of next, react and react-dom, and how far you are behind the latest release. npx next -v prints just the Next.js version.
See why you have that version
npm ls next (or pnpm why next) shows which version is installed and through which package. If your lockfile (package-lock.json or pnpm-lock.yaml) is not committed, the version can change on every build, so commit it first.
Check the version running in production
Updating locally does not change a server still running an old image. For a container, read the version field of next's package.json inside the running container (command below). This also works with output: 'standalone'.
Match against known CVEs
npm audit --omit=dev checks only the dependencies that ship to production. Adding --audit-level=high makes it exit non-zero when anything High or above is found, so CI can stop on it. Scanning the lockfile with osv-scanner serves the same purpose.
Read the official advisory for your setup
Next.js advisories sometimes split by App Router vs Pages Router, or by self-hosted vs managed. Compare the fixed versions listed in the advisory with the versions you found in steps 1 to 3.
# local: actual versions and distance from latest
npx next info
# the version running inside the production container
docker exec <container> node -p "require('next/package.json').version"
# check only production dependencies; fail on High or above
npm audit --omit=dev --audit-level=highWhat changes with how you run it
The same CVE can affect you or not depending on how you run Next.js. Two past cases, by deployment type:
| How you run it | Middleware auth bypass (CVE-2025-29927) | RSC RCE (CVE-2025-55182) | Who updates |
|---|---|---|---|
| Managed (Vercel, Netlify, etc.) | Not affected (routing runs in a separate system) | Affected if you use App Router; blocking rules exist but you still must update | You (your lockfile decides the next version) |
| Self-hosted (next start / standalone, incl. Docker) | Affected | Affected if you use App Router | You (through rebuilding the image and restarting) |
| Static export (output: 'export') | Not affected (no server runs) | No server receives requests, so it generally does not reach you | You (build-time dependencies still need updates) |
So even on managed hosting, raising the Next.js version is your job. Treat the host's protections as buying time until you are on the patched version.
Check the support window too. Per the official support policy, as of October 2026:
| Line | Status (October 2026) | Security fixes |
|---|---|---|
| 16.x | Active LTS (features, fixes, security patches) | Yes |
| 15.x | Maintenance LTS (two years from initial release) | Critical ones only |
| 14.x and older | Unsupported | Rarely, for severe issues, with no guarantee |
2. Machine-monitor your dependencies
Tracking CVEs by hand doesn't hold up, and the miss becomes the incident. Monitor them automatically with a tool.
Free dependency monitoring
osv-scanner scan -L pnpm-lock.yamlOn GitHub, enable Dependabot (the repository's Settings → Advanced Security → Dependabot alerts). You'll get PRs only for CVEs that match your deps.
What matters is prioritization. This site's stance: rank by "is it being exploited (KEV)" times "how high is the CVSS." A high CVSS you don't use is small impact; a mid-score under active exploitation is top priority. That prioritization is the core of the work.
3. Updating: move to the fixed version, not a workaround
When a vulnerability appears, upgrade the framework to the patched version to fix the vulnerability itself.
Surface-level fixes (insufficient)
- Block only requests that look like the attack at a reverse proxy
- Stop the charges/symptom and call it "handled"
- Leave the RCE vulnerability itself in place
Root fix (correct)
- Upgrade the framework to the patched version
- After upgrading, confirm the signature is gone in your logs
- Treat stopping the damage and fixing the root cause as two separate jobs, and do both
The common failure
"Stopped the charges/symptom" ≠ "handled." Stopping the damage and fixing the vulnerability are different jobs. Do both.
A real example: the December 2025 React Server Components vulnerability
Here is what handling a published CVE actually looked like, using the React Server Components (RSC) vulnerability disclosed in December 2025. Everything below comes from the official React and Next.js announcements and CISA's public data.
December 3, 2025
React disclosed CVE-2025-55182 (CVSS 10.0), which can lead to code execution on the server without authentication. In Next.js, App Router apps on 15.x, 16.x and some canaries were affected (CVE-2025-66478); Pages Router and the Edge Runtime were not. There was no workaround: upgrading to a fixed version (15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7, 16.0.7 and others) was required.December 5, 2025
CISA added it to its catalog of vulnerabilities confirmed as exploited in the wild (KEV).December 6, 2025
Next.js added that apps online and unpatched as of December 4, 1:00 PM Pacific should rotate the secrets they use (API keys and so on).December 11, 2025
While the patch was being examined, two more issues in the same mechanism (denial of service and source code exposure) were found and patched. The denial-of-service fix then proved incomplete, CVE-2025-67779 was issued, and people who had already upgraded were asked to upgrade again.
Three operational lessons follow:
- One update is not the end. Follow-up fixes to the same code can arrive days apart
- The host's blocking rules were a supplement; upgrading was described as the only complete fix
- If you were online before patching, rotate secrets as well as updating
This site's view: done means the production version is patched, not that you ran an update
When follow-up fixes keep coming, as here, "I upgraded last week" stops being reliable. Judge completion by whether the version running in production is at or above the fixed version in the latest advisory, not by memory of the work. This site, too, only marks an update done after confirming the container was recreated and checking the version running inside it.
Common mistakes and fixes
- Judging by the number in package.json: the installed version may differ. Check with
npx next infoornpm ls next. - Stopping after updating the lockfile: the old version keeps running until the production image is rebuilt and restarted. Check the version inside production.
- Feeling safe after one update: follow-up advisories can come. Keep Dependabot or similar alerts on and watch advisories for a few days.
- Leaving it to the host's blocking rules: they may not catch every form of an attack. Upgrade.
- Staying on an unsupported line: 14.x and older have no guarantee of fixes. Plan the move to 16.x.
- Missing production-relevant warnings among dev-only noise: run
npm audit --omit=devto see what ships first. - Ignoring the window before you patched: secrets may have been taken in that time. Rotate API keys and database passwords (→ .env and API key basics).
4. Least privilege to limit the damage
Design so that damage stays limited if the app is exploited.
Run as a non-privileged user
USER as root. A breach then reaches only what that user is allowed to do.Bind DB/Redis to the internal network only
Separate per service
These decide whether a breach stops at "env theft inside a container" or reaches "host takeover."
We do this ourselves
This site monitors its own dependencies for CVEs, exactly as written here — so that the kind of miss that started it all (a neglected public CVSS 10.0) isn't left to human attention again. We say "rank by priority (KEV + CVSS)" because that's how we actually operate.
Read next
- Incident: A neglected public RCE billed for fraud
- Glossary: CVE · CVSS · RCE
- History: Log4Shell — RCE through a dependency
- By framework: Next.js security (the boundary, env vars, dependency CVEs)
- Prioritizing: ranking CVEs with CVSS, EPSS and KEV
- Monitoring: setting up osv-scanner
- The landscape: do Next.js and React have a lot of vulnerabilities? (what the CVE data actually shows)
Sources
- Next.js, "Security Advisory: CVE-2025-66478" (December 3, 2025; updated December 6): nextjs.org
- Next.js, "Security Update: December 11, 2025" (CVE-2025-55183 / 55184 / 67779): nextjs.org
- NVD, "CVE-2025-55182": nvd.nist.gov / CISA, "Known Exploited Vulnerabilities Catalog": cisa.gov
- Vercel, "React2Shell Security Bulletin": vercel.com
- Vercel, "Postmortem on Next.js Middleware bypass" (CVE-2025-29927): vercel.com
- Next.js, "Support Policy": nextjs.org / "next CLI": nextjs.org / "Static Exports": nextjs.org
- npm Docs, "npm audit": docs.npmjs.com / OSV-Scanner, "Usage": google.github.io / GitHub Docs, "Configuring Dependabot alerts": docs.github.com