Decrypt Firefox passwords in your browser
2026-06-21 · 3 min
Firefox saved passwords live in two files, not one. logins.json holds the
encrypted usernames and passwords; key4.db holds the key that decrypts
them. Hand the tool both files, supply the primary password if one is set
(usually it isn't), and you get cleartext credentials — without NSS, without
a Firefox install, and without anything leaving the machine.
1. Acquire the two files
Both sit in the profile root, the randomly-named
Profiles/<xxxx>.default-release/ folder:
| File | Role | Format |
|---|---|---|
logins.json | encrypted usernames + passwords | JSON, base64 ASN.1 blobs |
key4.db | the key store | SQLite |
key3.db | key store on pre-2018 Firefox | Berkeley DB |
Modern Firefox uses key4.db. If the profile predates 2018 you'll find
key3.db instead — grab whichever is present. You need the key store and
logins.json together; one without the other is useless. Note that
cookies.sqlite is not in this picture: Firefox stores cookie values in
cleartext, so no key is involved (see
browser cookies in forensics).
2. What's inside each file
logins.json is an array of entries. Each encryptedUsername and
encryptedPassword is a base64-wrapped ASN.1 structure: it names the
3DES-CBC algorithm, carries the IV, and holds the ciphertext. The login
values themselves are always 3DES-CBC, regardless of Firefox version.
key4.db is SQLite. Two tables matter:
metaData— a row keyedpasswordholds the global salt and a password-check blob used to validate the primary password.nssPrivate— thea11row holds the wrapped 3DES key that actually decrypts the login entries.
The wrapping of that a11 key has changed over time:
| Firefox era | Key wrapping |
|---|---|
| modern | AES-256, PBES2-derived |
| older | 3DES PBE |
Either way, once the a11 key is unwrapped, every login entry is decrypted
with 3DES-CBC.
3. The primary password
By default Firefox sets no primary password (formerly "master password"), so the leave-it-blank case is the common one. If the user set one, it is required to unwrap the key — there's no bypass.
The decryption is self-validating. NSS checks the entered password against
the password-check blob in metaData before touching any login. A wrong
password fails cleanly; it never produces garbage plaintext. So if the tool
returns credentials, they're real — and if it rejects the password, you know
to keep looking for the right one.
4. Decrypt it
- Load
key4.db(orkey3.db) andlogins.json— drop both onto the tool. - Enter the primary password. Leave it blank if none was set.
- Click decrypt.
The work runs in a Rust/WASM NSS module entirely in the browser tab: global
salt + primary password derive the wrapping key, that unwraps the a11
3DES key, and that decrypts each entry in logins.json. Nothing is
uploaded. The output is a table of hostname, username and password per
login.
5. What you get back
Each row maps to a logins.json entry: hostname, the decrypted
username, the decrypted password, plus the timeCreated,
timeLastUsed and timePasswordChanged timestamps Firefox keeps
alongside. Those timestamps are worth pulling into a timeline — they show
when a credential was first saved and last used, independent of browsing
history (see where browser passwords are
stored).
Mechanics vs. method
This post is the practical how-to. The byte-level walkthrough — the ASN.1
layout, the PBES2 / 3DES key derivation, and how the password-check round
actually works — lives in the
Firefox NSS deep-dive. Read that
one if you need to verify the crypto rather than just run it.