
Proof-of-concept exploit for CVE-2025-29927, a Next.js middleware authorization bypass. Includes a vulnerable target lab and Python script to verify the bypass by sending crafted x-middleware-subrequest headers.
A small GitHub project for verifying CVE-2025-29927 (Next.js Middleware Authorization Bypass) in a local authorization lab (VMware: Ubuntu target VM + Kali attacker VM).
⚠️ Disclaimer: This project is intended solely for security education, CTF, and lab environments that you own or are explicitly authorized to test. It is strictly prohibited to use it against any unauthorized system. The user bears sole responsibility for any consequences resulting from misuse of this project.
| Item | Details |
|---|---|
| CVE | CVE-2025-29927 |
| Disclosure Date | 2025-03-25 (Next.js official security advisory) |
| Affected Component | Vercel Next.js (Node.js full-stack framework) |
| Vulnerability Type | Authorization Bypass / Improper Authorization (CWE-863) |
| Affected Versions | < 12.3.5, < 13.5.9, < 14.2.25, < 15.2.3 |
| Fixed Versions | 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3 and above |
| Severity Rating | Critical / High (refer to the NVD page for the exact score) |
After the vulnerability was disclosed, numerous production admin panels, payment callbacks, and internal APIs were bypassed. Both Metasploit and ProjectDiscovery Nuclei have included detection modules, making it one of the most representative "framework-level authorization bypass" vulnerabilities of 2025.
Next.js allows you to put "authentication logic" in middleware, for example:
export function middleware(request) {
if (!isLogin(request)) return NextResponse.redirect("/login"); // not logged in → block
return NextResponse.next();
}
The problem is that Next.js internally relies on a client-forgeable request header to determine whether "this request has already executed middleware":
x-middleware-subrequest: middleware
In affected versions, as long as an external request carries this internal header, Next.js mistakenly assumes the middleware has already run, and thus the entire authentication middleware is skipped. An attacker needs no account — simply sending this header when accessing protected routes like /admin returns a 200 directly. Since the page itself typically trusts the middleware and performs no secondary validation, the authorization check is defeated (trust boundary error).
💡 The most common payload in public exploits is the form where the middleware path is repeated and concatenated, e.g.
middleware:middleware:middleware:middleware:middleware; a singlemiddlewaredoes not work in some versions/directory structures (confirmed in this lab with 14.2.24). This PoC iterates through multiple candidate values, and a bypass succeeds if any one of them hits.
CVE-2025-29927-PoC/
├── README.md # This document (vulnerability description + VMware lab tutorial)
├── LICENSE # MIT
├── .gitignore
├── exploit.py # ★ Python3 pure standard library verification PoC (runs on Kali/any machine)
├── target/ # ★ Self-built vulnerable lab (copy to Ubuntu target VM)
│ ├── package.json # Pins [email protected] (affected version)
│ ├── middleware.js # Simulates a real production "authentication middleware"
│ ├── pages/
│ │ ├── index.js # Home page
│ │ ├── login.js # Login page (demonstrates being redirected here)
│ │ └── admin.js # ★ Protected admin panel, server-side reads flag.txt
│ ├── flag.txt # Lab flag: FLAG{...}
│ ├── setup.sh # One-click target VM setup: install Node 20 + npm install + build
│ └── start.sh # Listen on 0.0.0.0:3000 in production mode
└── tests/
└── mock_target.py # Node-free mock target (for development self-testing only)
┌───────────────────────────────────────────────────────────┐
│ VMware Workstation Pro 17 (Host: Windows) │
│ Network: NAT (default VMnet8), both VMs on the same subnet, mutually pingable │
│ │
│ ┌──────────────────┐ ┌─────────────────────┐ │
│ │ Target Ubuntu 24.04 │ │ Attacker Kali Linux │ │
│ │ │ http │ │ │
│ │ Node 20 + Next │◄───────│ python3 exploit.py │ │
│ │ 14.2.24 :3000 │ GET │ │ │
│ └──────────────────┘ └─────────────────────┘ │
│ IP: <TARGET_IP> IP: <ATTACKER_IP> │
└───────────────────────────────────────────────────────────┘
| Purpose | Image/Software | Recommended Version |
|---|---|---|
| Virtualization software | VMware Workstation Pro 17 (free for personal use) | 17.x |
| Target VM image | Ubuntu Server LTS ISO | 24.04.x |
| Attacker VM | Kali Linux (official VMware pre-built image or ISO install) | 2025.x |
| (Optional) | Host machine with 8 GB+ RAM, 50 GB+ disk | — |
All the following steps are performed on the Ubuntu target VM.
# Option A: Push the project to your own GitHub and clone it (recommended; use this if you plan to push to GitHub later)
git clone https://github.com/<your-username>/CVE-2025-29927-PoC.git
cd CVE-2025-29927-PoC
# Option B: scp from the host machine
# scp -r CVE-2025-29927-PoC ubuntu@<TARGET_IP>:~/
cd CVE-2025-29927-PoC/target
sudo bash setup.sh # Installs Node 20 (LTS) + npm install + next build
What setup.sh does internally: update apt → install curl/CA/build tools → install Node.js 20 LTS via NodeSource → npm install (pulls [email protected] and other dependencies) → npm run build.
bash start.sh
# Seeing "▲ Next.js 14.2.24" and "Local: http://0.0.0.0:3000" means success
Open another terminal and run a local smoke test first:
curl -s http://127.0.0.1:3000 # Home page, 200
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/admin
# Expected output 307 — blocked by middleware without cookie (authentication working normally)
curl -s http://127.0.0.1:3000/admin # Observe that the body should be the redirected login page content