1402307692/CVE-2026-Mastodon-Streaming-Token-Leakage

GitHub: 1402307692/CVE-2026-Mastodon-Streaming-Token-Leakage

Mastodon Streaming Server OAuth Access Token URL 查询参数泄露漏洞的概念验证,演示了 Token 在多种日志记录面上暴露的风险。

Stars: 0 | Forks: 0

# CVE-2026-XXXXX: Mastodon Streaming Server 中通过 URL 查询参数泄露 OAuth Access Token ## 漏洞概述 | 项目 | 详情 | |------|---------| | CVE ID | CVE-2026-XXXXX | | 受影响产品 | Mastodon (Streaming Server) | | 受影响版本 | <= 4.5.9 | | 组件 | streaming/index.js 第 385-401 行 | | 漏洞类型 | 通过查询字符串暴露敏感信息 | | CWE | CWE-598 | | CVSS 3.1 | 7.5 (高危) | | 攻击向量 | 网络 | | 报告者 | qitian | ## 漏洞描述 streaming/index.js 第 385-401 行的 accountFromRequest() 函数接受来自 URL 查询字符串的 OAuth access token: ``` // streaming/index.js lines 385-401 const accountFromRequest = (req) => new Promise((resolve, reject) => { const authorization = req.headers.authorization; const location = req.url ? url.parse(req.url, true) : undefined; const accessToken = location?.query.access_token || req.headers['sec-websocket-protocol']; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // access token accepted from URL query string if (!authorization && !accessToken) { reject(new AuthenticationError('Missing access token')); return; } const token = authorization ? authorization.replace(/^Bearer /, '') : accessToken; // token from query string used as authentication credential resolve(accountFromToken(token, req)); }); ``` 当 WebSocket 客户端在 URL 中使用 ?access_token=... 进行连接时,OAuth token 会出现在多个日志记录面上: 1. **浏览器历史记录** — URL 存储在地址栏、书签、历史记录中 2. **反向代理日志** — Nginx、Apache 默认的访问日志会记录包含查询字符串的完整 URL 3. **CDN 日志** — Cloudflare、CloudFront 及其他 CDN 提供商会记录完整的 URL 4. **Referer 头** — 当用户导航到其他页面时,浏览器会在 Referer 头中发送完整的 URL(包含 token) 5. **服务器应用程序日志** — Mastodon 会记录包含查询字符串的完整请求 URL 6. **SIEM/监控系统** — 链接跟踪工具、UTM 网关、安全扫描器会记录完整的 URL ## 影响 - 任何有权访问服务器日志、代理日志、CDN 日志或浏览器历史记录的人都可以提取 URL 中的 OAuth token - Token 窃取会导致**完全的账户接管** — 读取时间线、通知、私信、执行关注/取关操作 - 由于广泛的日志记录面,此风险显著高于基于请求头的 token 传输方式 ## 概念验证 ### PoC 1 - 从 URL 查询中接受 Token (WebSocket) ``` # 使用 wscat 或 websocat wscat -c "ws://TARGET:4000/api/v1/streaming/user?access_token=YOUR_OAUTH_TOKEN" # 或者使用 Python python3 -c "import websocket; ws = websocket.create_connection('ws://TARGET:4000/api/v1/streaming/user?access_token=YOUR_OAUTH_TOKEN'); print(ws.recv())" ``` 预期结果:服务器接受使用 URL 查询参数中 token 的连接请求。 ### PoC 2 - URL 中包含 Token 的 HTTP 请求 ``` # Token 位于 URL 中 — 会被记录到所有日志中 curl -i "http://TARGET:4000/api/v1/streaming/user?access_token=YOUR_OAUTH_TOKEN" ``` ### PoC 3 - 演示日志暴露 ``` # 这是出现在 Nginx 访问日志中的内容: # "GET /api/v1/streaming/user?access_token=YOUR_OAUTH_TOKEN HTTP/1.1" # 任何拥有日志访问权限的攻击者都可以提取并重用该 token ``` ### PoC 4 - 与 Authorization 头对比(安全方式) ``` # 正确方法 — token 位于 header 中,默认不会被记录 curl -i -H "Authorization: Bearer YOUR_OAUTH_TOKEN" "http://TARGET:4000/api/v1/streaming/user" ``` ## 修复方案 **完全移除对 URL 查询 token 的接受:** ``` const accountFromRequest = (req) => new Promise((resolve, reject) => { const authorization = req.headers.authorization; // REMOVE: accessToken from URL query string if (!authorization) { reject(new AuthenticationError('Missing access token')); return; } const token = authorization.replace(/^Bearer /, ''); resolve(accountFromToken(token, req)); }); ``` 对于 WebSocket 客户端:请改用 Sec-WebSocket-Protocol 头(在大多数反向代理中默认不记录此头)。 ## 时间线 | 日期 | 事件 | |------|-------| | 2026-04-22 | 发现漏洞并创建 PoC | | 2026-04-22 | 向 MITRE / VDB 提交 CVE 报告 | ## 参考文献 - https://github.com/mastodon/mastodon - https://cwe.mitre.org/data/definitions/598.html - OWASP: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html 免责声明:此 PoC 仅用于教育和安全研究目的。
标签:Access Token, CISA项目, CVE, CWE-598, GNU通用公共许可证, Mastodon, MITM代理, Node.js, OAuth, PoC, Referer泄露, URL查询参数, WebSocket, Web安全, 中间人攻击, 云资产清单, 令牌泄露, 依赖分析, 分布式拒绝服务攻击防御, 数字签名, 日志泄露, 暴力破解, 流媒体服务器, 漏洞分析, 网络安全, 蓝队分析, 路径探测, 身份验证绕过, 逆向工程, 隐私保护