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:
| Column | What it tells you |
|---|---|
origin_url | the page the form was on |
action_url | where the form posted |
signon_realm | the credential's scope (origin, or an HTTP auth realm) |
username_value | the saved username — cleartext |
password_value | the saved password — encrypted blob |
date_created | when the credential was first saved |
date_last_used | last time it was autofilled |
times_used | autofill count |
blacklisted_by_user | the "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.