browserforensics
Back to all articles

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.

ColumnMeaning
idRow primary key
hostDomain the cookie belongs to (leading dot = wildcard)
nameCookie name
valueCleartext cookie value — no decryption needed
pathURL path scope
isSecure1 = HTTPS only
isHttpOnly1 = not exposed to JavaScript
sameSiteSameSite policy (0 none, 1 lax, 2 strict)
expiryExpiry — plain Unix seconds
lastAccessedLast use — PRTime (microseconds)
creationTimeFirst set — PRTime (microseconds)
originAttributesContainer / 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.

FieldFormatConversion
creationTimePRTime — microseconds since 1970/ 1000000 for Unix seconds
lastAccessedPRTime — microseconds since 1970/ 1000000 for Unix seconds
expiryPlain Unix seconds since 1970use 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. host plus 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 History and forget Cookies. The cookie table frequently survives the wipe and reconstructs the same domain timeline.
  • Session continuity. lastAccessed advancing over days tells you the session was kept alive, not a single drive-by visit.

Pitfalls

  • expiry of 0 (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 host means the cookie applies to the domain and its subdomains; trim it before comparing against a URL host.
  • Don't skip the -wal sidecar. 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.

Further reading