Firefox cookies forensics (cookies.sqlite)
2026-06-21 · 4 min
Firefox cookies are easier evidence than their Chromium equivalent for one
reason: the values are stored in cleartext. There is no DPAPI key to recover,
no Keychain to unlock, no AES-GCM blob to decrypt — the session token sits in
the database in plain text. Combine that with three timestamps per row and
cookies.sqlite becomes both a timeline source and a place where live
credentials leak.
Where it lives
cookies.sqlite is a SQLite database in the Firefox profile root, alongside
places.sqlite. It runs in WAL mode, so grab the cookies.sqlite-wal
sidecar with matching base name — recently set or deleted cookies may live
there and never appear if you parse the main file alone.
The moz_cookies schema
There is one table that matters: moz_cookies, one row per cookie.
| Column | Meaning |
|---|---|
id | Row primary key |
host | Domain the cookie belongs to (leading dot = wildcard) |
name | Cookie name |
value | Cleartext cookie value — no decryption needed |
path | URL path scope |
isSecure | 1 = HTTPS only |
isHttpOnly | 1 = not exposed to JavaScript |
sameSite | SameSite policy (0 none, 1 lax, 2 strict) |
expiry | Expiry — plain Unix seconds |
lastAccessed | Last use — PRTime (microseconds) |
creationTime | First set — PRTime (microseconds) |
originAttributes | Container / private-browsing tagging |
The contrast with Chromium is the whole point. Chrome and Edge encrypt the cookie value at rest (AES-256-GCM, key wrapped by DPAPI / Keychain), so without the profile keys you get metadata only. Firefox hands you the value.
The cleartext value column
Because value is plain text, anything the browser stored is directly
readable: session identifiers, auth tokens, OAuth state, CSRF tokens, and the
opaque blobs that map to a logged-in account on a given service. An
isHttpOnly = 1 cookie that you could never reach from page JavaScript is
still sitting in the database for you to read.
Treat that with the care it deserves. A live session token recovered from
cookies.sqlite can often be replayed to impersonate the user — which makes
it powerful evidence and a handling risk at the same time. Note the cookie,
do not casually paste it around.
originAttributes: containers and private browsing
originAttributes tags the cookie's isolation context. It carries the
container ID for Multi-Account Containers and the private-browsing flag, so
two cookies for the same host and name can coexist in different
compartments. Read it before you assume two rows are duplicates — they may be
a normal-window cookie and a container (or private) cookie that never share
state.
The three timestamps
Each row carries three time fields, and they do not use the same epoch — the single most common parsing error on Firefox cookies.
| Field | Format | Conversion |
|---|---|---|
creationTime | PRTime — microseconds since 1970 | / 1000000 for Unix seconds |
lastAccessed | PRTime — microseconds since 1970 | / 1000000 for Unix seconds |
expiry | Plain Unix seconds since 1970 | use as-is |
So creationTime and lastAccessed divide by a million; expiry does not.
Apply the PRTime conversion to expiry and you land tens of thousands of
years in the future.
creation_unix = creationTime / 1000000
lastaccess_unix = lastAccessed / 1000000
expiry_unix = expiry
Three timestamps per cookie is strong timeline material. creationTime
pins when the user first hit a site; lastAccessed shows when they last had
an active session there. Overlay those against places.sqlite visits and a
download row at the same second and you can place a specific account-bearing
session in the timeline — even if history was cleared but the cookie store
was not.
What cookies reconstruct
- Which sites were active, and when.
hostplus the creation/last-access pair shows the set of domains the profile held sessions for and the window of use. - Logged-in accounts. A persistent auth cookie for a webmail or banking host is evidence the user had an account there.
- Cleared-history recovery. Users wipe
Historyand forgetCookies. The cookie table frequently survives the wipe and reconstructs the same domain timeline. - Session continuity.
lastAccessedadvancing over days tells you the session was kept alive, not a single drive-by visit.
Pitfalls
expiryof0(or a past value) means a session cookie that the browser did not persist long — do not render it as 1970-01-01 and call it a date.- A leading dot on
hostmeans the cookie applies to the domain and its subdomains; trim it before comparing against a URL host. - Don't skip the
-walsidecar. Recently set and recently deleted cookies may only exist there until the next checkpoint.
BrowserForensics parses moz_cookies directly in the browser — values,
flags, originAttributes and all three timestamps decoded — and applies the
WAL so the most recent cookie activity is included. Nothing leaves the
machine.