Skip to main content

firefox-logins

Read and write Firefox saved passwords, by driving the browser's own NSS Secret Decoder Ring through ctypes.

Plenty of tools decrypt logins.json. This one also seals new credentials into it, using the same code path Firefox itself uses — so entries it writes are indistinguishable from ones you saved by hand. That makes browser-to-browser password migration possible without a plaintext CSV round trip.

No runtime dependencies: the crypto comes from the Firefox install already on the machine.

Install

pip install firefox-logins

Requires Python 3.11+ and a Firefox installation. Tested on macOS; Linux paths are supported but less exercised.

Usage

Read

from firefox_logins import LoginStore

with LoginStore.open() as store:
    for login in store:
        print(login.hostname, login.username, login.password)

LoginStore.open() uses the profile Firefox would launch. Pick another with find_profiles(), and pass primary_password= if the profile has one.

Write

from firefox_logins import Login, LoginStore

with LoginStore.open() as store:
    store.add(Login(
        hostname="https://example.com",
        username="ada",
        password="hunter2",
        form_submit_url="https://example.com",
    ))
    written = store.save()   # Firefox must be quit

save() decrypts every entry — existing and new — before replacing the file, and abandons the write if any fails. It backs up to logins.json.bak, writes to a staging file, then renames, so an interrupted run cannot leave a partial file where your credentials were.

Set exactly one of form_submit_url (form logins) or http_realm (HTTP auth); Firefox rejects entries with both or neither, so the constructor does too.

Profiles

from firefox_logins import find_profiles

for profile in find_profiles():
    print(profile.name, profile.path, profile.is_default)

Low-level

from firefox_logins import SecretDecoderRing, keyid_from_blob

with SecretDecoderRing("/path/to/profile") as sdr:
    sdr.selftest()
    blob = sdr.encrypt("secret")
    assert sdr.decrypt(blob) == "secret"

Notes on the write path

Four things are needed to seal a value the way Firefox does, none of them covered by the read-only references this was built against. They are recorded here because each one fails in a way that is easy to misdiagnose:

  1. libnss3 declares @rpath/libmozglue, which the loader cannot resolve from a host process. The dependency is loaded by absolute path first, and the working directory stays inside the Firefox bundle through NSS_Init, because NSS dlopens softokn and freebl during initialisation.
  2. Firefox does not export PK11SDR_Encrypt — only PK11SDR_EncryptWithMechanism.
  3. The mechanism must be CKM_AES_CBC. CKM_AES_CBC_PAD and both DES3 forms return SEC_ERROR_INVALID_ARGS, because the Secret Decoder Ring applies PKCS#7 padding itself rather than delegating it to PKCS#11.
  4. The key id must be non-empty. NSS's default is f8000000000000000000000000000001; keyid_from_blob() recovers a profile's own from any entry it already holds, since the stored value is DER SEQUENCE { OCTET STRING keyid, AlgorithmIdentifier, OCTET STRING ciphertext }.

selftest() runs a seal/unseal round trip and is called automatically when a LoginStore is opened, so a wrong mechanism or key id fails immediately rather than producing a file Firefox silently cannot read.

Scope and safety

This reads and writes credentials belonging to the user running it, using keys already present in that user's own profile. It grants no access that running as that user does not already imply, and it cannot bypass a Primary Password — without the correct one, NSS refuses to unlock the key slot.

If a profile has a Primary Password, pass it:

LoginStore.open(primary_password="…")

Quit Firefox before writing. Firefox rewrites logins.json on exit, so changes made while it runs are discarded; save() refuses by default and explains why.

Companion

chromium-reader does the equivalent job for Chromium's on-disk storage formats.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

firefox_logins-0.1.0.tar.gz (17.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

firefox_logins-0.1.0-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file firefox_logins-0.1.0.tar.gz.

File metadata

  • Download URL: firefox_logins-0.1.0.tar.gz
  • Upload date:
  • Size: 17.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for firefox_logins-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8230db7ace1ad0f465b5a9a1a4ce26c8518b2d8f19563cba21ee1d67fe7fdd3e
MD5 32ee760e122a5d0c9ab8c869ab1b6cdc
BLAKE2b-256 35cf7171cb2653b62336d73f60a7c8c50682012c6eb5a7f1fd7f35c9482cdcb3

See more details on using hashes here.

Provenance

The following attestation bundles were made for firefox_logins-0.1.0.tar.gz:

Publisher: publish.yml on DJRHails/firefox-logins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file firefox_logins-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: firefox_logins-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for firefox_logins-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 df167f00a1784194764d3d537114b658c497c8e8f71823d0f440f4cdd585718b
MD5 a5b8b442f602938e462165a59642bcc5
BLAKE2b-256 5b6b6aa0bc13da0ecce050c52eb10faede93614d1170a4a7cb8517306befa44b

See more details on using hashes here.

Provenance

The following attestation bundles were made for firefox_logins-0.1.0-py3-none-any.whl:

Publisher: publish.yml on DJRHails/firefox-logins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page