browserforensics
Back to all articles

Chrome Login Data: saved-password forensics

2026-06-21 · 4 min

Most analysts reach for Login Data to recover passwords. That is the loudest finding, but it is often the least useful one. The same database quietly enumerates every site where the user kept an account, the usernames they used, and when each credential was last touched — and it does all of that whether or not you ever decrypt a single password_value.

Where it lives

Login Data is a SQLite database in the profile folder, identical in Chrome and Edge:

%LOCALAPPDATA%\Google\Chrome\User Data\<profile>\Login Data
%LOCALAPPDATA%\Microsoft\Edge\User Data\<profile>\Login Data

Grab the -wal sidecar alongside it. Recently saved or updated credentials may sit in the write-ahead log, not yet checkpointed into the main file, and skipping it loses rows. On profiles signed into a Google or Microsoft account, account-scoped credentials live in a second file, Login Data For Account, with the same schema — collect both.

The logins table

Everything of interest is one table, logins. The columns that matter:

ColumnWhat it tells you
origin_urlthe page the form was on
action_urlwhere the form posted
signon_realmthe credential's scope (origin, or an HTTP auth realm)
username_valuethe saved username — cleartext
password_valuethe saved password — encrypted blob
date_createdwhen the credential was first saved
date_last_usedlast time it was autofilled
times_usedautofill count
blacklisted_by_userthe "Never save" flag

username_value is stored in the clear. So is every URL. That means the account inventory — which sites, which usernames — is readable from the raw file with nothing but a SQLite viewer.

"Never save" entries are evidence

When a user clicks Never on a save prompt, Chromium does not discard the event. It writes a row with blacklisted_by_user = 1, the site's origin_url, and an empty password_value. The user declined to store the password, but the database now records that they had an account worth declining on that site, and roughly when. Treat blacklist rows as visit evidence, not as noise.

The encrypted password

password_value is the same encryption scheme as cookie values: a v10/v20 AES-256-GCM blob keyed by the profile's os_crypt key. On disk it is ciphertext — version tag, 12-byte nonce, ciphertext, 16-byte tag — and you need the Local State key (DPAPI-wrapped on Windows) to read it. The format and key chain are covered in how Chromium encrypts cookies on Windows; the practical recovery steps are in decrypt saved passwords and credit cards.

The metadata above does not depend on any of that. Decrypt password_value only when the case actually turns on the secret — proving credential reuse, or that a specific account password was held on the host.

Timestamps

date_created and date_last_used are WebKit timestamps: microseconds since 1601-01-01 UTC, not Unix seconds. A raw SQLite dump shows a 17-digit integer; render it through the WebKit epoch or every date will be wrong by centuries. times_used paired with date_last_used separates a credential that was saved once and forgotten from one in daily use. See browser timestamp formats for the conversion.

What the database answers

  • Which sites the subject held accounts on, even with no password recovered.
  • The usernames — often a real identity, an email, or a handle that links to other artifacts.
  • A timeline: first save, last use, and how heavily each credential was used.
  • Sites the user explicitly refused to save — themselves a list of authenticated destinations.

For the full storage picture across browsers, see where browser passwords are stored.

Reading it with the tool

BrowserForensics parses the logins table client-side and shows the cleartext columns — URLs, usernames, timestamps, the blacklist flag — immediately, with no key. Supply the os_crypt key and it decrypts password_value in the browser, the same path it uses for cookie values. Nothing leaves the page.

Further reading