Firefox
Firefox Saved Passwords
Overview
Firefox stores saved login credentials in logins.json, a JSON file within each profile directory. Usernames and passwords are encrypted using Mozilla's NSS (Network Security Services) library, with encryption keys stored in key4.db. An optional master password adds an additional layer of protection.
Forensic analysis of saved logins focuses on metadata rather than credential recovery: which sites have saved credentials, when they were created and last used, how frequently they were used, and which sites have password saving explicitly disabled. The macfor collector never attempts to decrypt passwords.
File Locations
| File | Path | Description |
|---|---|---|
| Saved logins | ~/Library/Application Support/Firefox/Profiles/{profile}/logins.json | Encrypted credentials |
| Key database | ~/Library/Application Support/Firefox/Profiles/{profile}/key4.db | NSS encryption keys |
| Certificate DB | ~/Library/Application Support/Firefox/Profiles/{profile}/cert9.db | Certificate storage |
All three files should be collected together to preserve the complete credential artifact set.
File Format
logins.json Structure
{
"nextId": 15,
"logins": [
{
"id": 1,
"hostname": "https://github.com",
"httpRealm": null,
"formSubmitURL": "https://github.com/session",
"usernameField": "login",
"passwordField": "password",
"encryptedUsername": "MDIEEPgA...",
"encryptedPassword": "MDoEEPgA...",
"guid": "{abc12345-def6-7890-abcd-ef1234567890}",
"encType": 1,
"timeCreated": 1685620800000,
"timeLastUsed": 1706227200000,
"timePasswordChanged": 1701388800000,
"timesUsed": 47
}
],
"version": 1,
"disabledHosts": [
"https://bank.example.com"
],
"potentiallyVulnerablePasswords": []
}
Top-Level Fields
| Field | Description |
|---|---|
nextId | Next ID to be assigned to a new login entry |
logins | Array of saved login entries |
version | File format version (typically 1) |
disabledHosts | Hostnames where user chose "Never save" when prompted |
potentiallyVulnerablePasswords | IDs of passwords flagged as potentially compromised |
Login Entry Fields
| Field | Description |
|---|---|
id | Unique integer identifier |
hostname | Origin URL (e.g., https://github.com) |
httpRealm | HTTP authentication realm (null for form-based logins) |
formSubmitURL | Form action URL (empty for HTTP auth) |
usernameField | HTML name attribute of the username input |
passwordField | HTML name attribute of the password input |
encryptedUsername | Base64-encoded, NSS-encrypted username |
encryptedPassword | Base64-encoded, NSS-encrypted password |
guid | Globally unique identifier (for Firefox Sync) |
encType | Encryption type (1 = SDR encryption via NSS) |
timeCreated | When credential was first saved (Unix milliseconds) |
timeLastUsed | When credential was last used for autofill (Unix milliseconds) |
timePasswordChanged | When the password was last updated (Unix milliseconds) |
timesUsed | Number of times the credential was used for autofill |
Key Fields for Analysis
| Field | Forensic Significance |
|---|---|
hostname | Which services the user has accounts on |
formSubmitURL | Login form endpoint (can reveal custom/internal applications) |
usernameField / passwordField | Field names that may identify the application framework |
timeCreated | When the user first saved this credential |
timeLastUsed | Most recent autofill usage |
timePasswordChanged | When password was last rotated |
timesUsed | Frequency of use (indicates active vs dormant accounts) |
disabledHosts | Sites where user explicitly declined password saving |
Timestamps
Login timestamps use Unix milliseconds (milliseconds since 1970-01-01 UTC), which differs from the PRTime format used in SQLite databases.
timeCreated = 1685620800000
Unix seconds = 1685620800000 / 1000 = 1685620800
Result = 2023-06-01T12:00:00Z
A value of 0 means the timestamp was not recorded.
Analysis Notes
Credential Inventory
Enumerate all sites with saved credentials to build a service inventory:
- The
hostnamelist reveals which web services the user accesses. - Cross-reference with browsing history to determine active vs. dormant accounts.
- The
formSubmitURLmay reveal internal corporate applications or staging environments.
Temporal Analysis
The three timestamps (timeCreated, timeLastUsed, timePasswordChanged) provide a credential lifecycle:
- timeCreated: When the user first trusted Firefox with this password.
- timeLastUsed: Last confirmed active use of the account.
- timePasswordChanged: Last password rotation. If this equals
timeCreated, the password has never been changed. - Gap analysis: A long gap between
timeCreatedandtimePasswordChangedmay indicate stale credentials.
Disabled Hosts
The disabledHosts array lists sites where the user clicked "Never save" when Firefox offered to save credentials. This is forensically relevant because:
- It confirms the user logged into these sites.
- It may indicate sites the user considers particularly sensitive (banking, healthcare).
- The decision to not save implies awareness of credential security.
Encryption Details
Firefox uses Mozilla NSS (Network Security Services) for credential encryption:
- key4.db: SQLite database containing encrypted master key material.
- Encryption type 1 (SDR): Secret Decoder Ring encryption, the standard method.
- Master Password: If set, adds an additional PKCS#5 encryption layer. Without the master password, offline decryption requires significantly more effort.
- The collector collects
key4.dbalongsidelogins.jsonto preserve the complete encryption context for offline analysis tools.
Potentially Vulnerable Passwords
The potentiallyVulnerablePasswords array contains IDs of logins that Firefox Lockwise has flagged as potentially compromised (e.g., via breach monitoring). The presence of entries here indicates the user received breach notifications.
Useful Queries on Parsed Records
Since logins.json is JSON rather than SQLite, analysis is performed on the parsed output:
- Sites with most logins used: Sort by
timesUseddescending. - Recently created credentials: Sort by
timeCreateddescending. - Stale accounts: Filter where
timeLastUsedis older than a threshold. - Never-changed passwords: Filter where
timePasswordChanged == timeCreated.
Version Differences
| Version | Change |
|---|---|
| Firefox 78 | key4.db replaces key3.db for NSS key storage |
| Firefox 76+ | Firefox Lockwise breach monitoring integration |
| Firefox 79+ | potentiallyVulnerablePasswords field added |
The logins.json format has been stable since its introduction. Older Firefox versions (pre-32) used a signons.sqlite database instead, but this is well outside the supported version range.
Tool Support
| Tool | Capability |
|---|---|
| macfor | Metadata extraction from logins.json, key4.db collection, no decryption (Pro module) |
| firefox_decrypt | Open-source Python tool for decrypting Firefox passwords (requires key4.db + optional master password) |
| firepwd | Python NSS credential decryptor |
| AXIOM | Automated Firefox credential extraction and analysis |
| NetworkMiner | Can extract saved credentials from Firefox profile data |