
Discovering CVE-2025-22381: Host Header Injection in the Aggie Open-Source Project
CVE-2025-22381:Aggie 中的主机头注入
针对 CVE-2025-22381 的详细分析和概念验证(PoC),该漏洞是 Aggie 开源项目中发现的一个主机头注入漏洞。
漏洞概述
CVE ID:CVE-2025-22381
发布时间:2025 年 10 月(MITRE 分配)
公开披露:2026 年 2 月
报告者:Anas Abderrahman Benbarek
发现日期:2025 年 9 月 17 日
受影响项目:TID-Lab/aggie
受影响版本:所有版本(包括 2.6.1 及更早版本;截至 2026 年 2 月未应用修复)
严重程度:中等到高(估计 CVSS ~7.1–7.5)
影响:可实现导致密码重置令牌窃取的钓鱼攻击,并可能造成账户接管。
背景
我花了不少时间在 GitHub 上审查开源的 Node.js 项目,尤其是那些处理认证流程的项目。2025 年 9 月,在查看 Aggie 代码库时,我注意到密码重置逻辑中有一个部分立即引起了注意。原本只是常规的代码审阅,最终却变成了 CVE-2025-22381 —— 一个经典的主机头注入漏洞,允许攻击者控制密码重置邮件中的域名。
我是如何发现的
我克隆了代码库,并开始阅读 lib/api/ 目录下的文件,重点关注与认证和邮件生成相关的内容。
文件 lib/api/reset-password.js 包含了 /reset-password 端点的逻辑。关键部分位于 sendEmail 辅助函数中:
function sendEmail(user, req, callback) {
var token = encodeToken(user);
mailer.sendFromTemplate({
template: 'forgotPassword',
user: user,
token: token,
host: req.headers.host, // ← 存在漏洞
protocol: req.protocol,
acceptLanguage: req.headers['accept-language']
}, callback);
}
host: req.headers.host 这一行就是问题所在。在 Express 中,req.headers.host 直接来自 HTTP 的 Host 头部,而这个头部完全由攻击者控制。代码中没有任何验证、白名单或回退到配置中的可信域名的机制。
初步确认
我按照 README 中的说明快速搭建了一个本地实例(Ubuntu, nvm, npm install, 带有测试 SMTP 的 secrets.json),启动服务器,并触发了一次密码重置。生成的邮件链接如预期使用了 localhost:3000。
然后,我用一个篡改后的 Host 头部重放了请求:
curl -X POST http://localhost:3000/reset-password \
-H "Host: evil-phish.example" \
-d "[email protected]"
邮件(通过 MailHog 捕获)中包含:
http://evil-phish.example/reset-password?token=...
确凿的证据。应用程序在构建重置链接时信任了客户端提供的 Host 头部。
攻击实际如何运作
Host 头部设置为其控制的域名(例如 evil-phish.example)。关键点:单纯的主机头注入本身并不允许攻击者直接使用令牌。攻击者仍然需要受害者访问恶意链接,以使令牌到达攻击者的基础设施。因此,这是一个辅助钓鱼的漏洞,而非无需用户交互即可直接接管账户的漏洞。
技术严重性与影响
根据上下文,这是一个中等到高严重性的问题:
许多数据库将其评为 CVSS ~7.1–7.5 范围。我个人认为,在生产环境中,当 Aggie 用于敏感监控(如选举、危机)时,这个问题是严重的,因为成功的钓鱼攻击可能导致完全接管账户。
概念验证(详细且可复现)
环境
.nvmrc)docker run -d -p 8025:8025 -p 1025:1025 mailhog/mailhog)email.transport 指向 localhost:1025逐步操作
克隆并启动 Aggie:
git clone https://github.com/TID-Lab/aggie.git
cd aggie
nvm install
npm install
cp config/secrets.json.example config/secrets.json
# 编辑 secrets.json → 设置 adminPassword,如果需要可添加测试 SMTP
npm start
通过 Web UI 或直接在 MongoDB 中创建一个测试用户。
触发恶意重置:
curl -i -X POST http://localhost:3000/reset-password \
-H "Host: evil-phish.example" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "[email protected]"
打开 MailHog:检查发送的邮件。重置链接将指向 http://evil-phish.example/reset-password?token=...
披露时间线
推荐的修复方案
代码更改
将 lib/api/reset-password.js 中有漏洞的行替换为可信值:
// 在 lib/api/reset-password.js 的 sendEmail() 函数中
const config = require('../../config/secrets').get();
// 选项 A:硬编码可信配置值(推荐用于单域名)
const host = config.appHost || 'localhost:3000';
// 然后使用它:
mailer.sendFromTemplate({
template: 'forgotPassword',
user: user,
token: token,
host: host, // 使用可信变量
protocol: config.environment === 'production' ? 'https' : req.protocol,
acceptLanguage: req.headers['accept-language']
}, callback);
配置
在 secrets.json 中添加:
"appHost": "https://your-real-domain.com"
总结与思考
主机头注入在 2025–2026 年仍然惊人地常见,尤其是在那些多年前启动且未经过严格审计的项目中。Aggie 是一个在公民技术和危机监控方面有价值的工具——我希望维护者能尽快应用修复。
如果你维护或使用 Aggie,请检查你的部署,并在官方发布之前手动打补丁。如果你有问题或想讨论其他项目中的类似问题,欢迎联系我。
感谢阅读,祝你安全。