browserforensics
Back to all articles

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:

FileRoleFormat
logins.jsonencrypted usernames + passwordsJSON, base64 ASN.1 blobs
key4.dbthe key storeSQLite
key3.dbkey store on pre-2018 FirefoxBerkeley 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 keyed password holds the global salt and a password-check blob used to validate the primary password.
  • nssPrivate — the a11 row holds the wrapped 3DES key that actually decrypts the login entries.

The wrapping of that a11 key has changed over time:

Firefox eraKey wrapping
modernAES-256, PBES2-derived
older3DES 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

  1. Load key4.db (or key3.db) and logins.json — drop both onto the tool.
  2. Enter the primary password. Leave it blank if none was set.
  3. 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.

Further reading