Firefox form history forensics
2026-06-21 · 3 min
formhistory.sqlite is one of the highest-signal artifacts in a Firefox
profile and one of the most overlooked. It captures the literal text a
user typed into web forms and the search bar — emails, usernames,
addresses, search queries — each with a usage count and first/last-used
timestamps. Where history tells you which pages were visited,
form history often tells you who the user is and what they were after.
Where it lives
formhistory.sqlite sits in the Firefox profile root, alongside
places.sqlite and cookies.sqlite. See
Firefox history file locations
for the per-OS profile paths.
It is Firefox's equivalent of Chrome's autofill store. If you work both browsers, the Chrome Web Data / autofill post covers the Chromium side of the same behaviour.
The moz_formhistory table
A single table carries everything:
| Column | Meaning |
|---|---|
id | Row identifier |
fieldname | The form field's name attribute (e.g. email, q, search) |
value | The exact text the user typed |
timesUsed | How many times this value was entered/reused |
firstUsed | First time this value was saved |
lastUsed | Most recent time it was used |
guid | Sync identifier |
The pairing of fieldname and value is what makes this artifact so
useful. A fieldname of email with a value of an address is a strong
identity indicator; a fieldname of q or search is almost always a
search-bar or site-search query, exposing intent in the user's own words.
The tool parses moz_formhistory directly and surfaces field, value,
timesUsed, and the first/last-used timestamps per row.
What the values reveal
- Identity — emails, usernames, full names, phone numbers and postal addresses typed into signup and checkout forms.
- Intent — search-bar queries and on-site searches. These are free-text and frequently more candid than visited URLs.
- Aliases — multiple values under the same
fieldname(several emails or usernames) suggest separate accounts or personas. - Frequency —
timesUsedranks how often a value was reused, which helps separate a primary identity from a one-off entry.
Because these are values the user typed rather than pages they landed on, they survive even when browsing history has been cleared, as long as form history itself was not also wiped.
Timestamps
firstUsed and lastUsed are stored as PRTime — microseconds since
the Unix epoch (1970). Divide by 1,000,000 for seconds before converting.
This is the same convention used across most of places.sqlite; the
browser timestamp formats post
documents the per-column exceptions you will hit elsewhere in Firefox.
firstUsed anchors when a value entered the profile; lastUsed shows the
most recent reuse. Together with timesUsed, they let you place a value
on a timeline and gauge its weight in the case.
Pitfalls
- A high
timesUseddoes not prove deliberate typing — autocomplete selection also increments it. Treat the count as reuse evidence, not keystroke evidence. fieldnameis attacker-controlled site markup, not a fixed taxonomy. Two sites may both call a fieldqoruser; do not assume a single field name maps to a single meaning across the whole table.- Form history can be cleared independently of history. An empty or
missing
formhistory.sqlitenext to a populatedplaces.sqliteis itself worth noting. - Like other Firefox SQLite stores it can run with WAL; pull the
-waland-shmsidecars together to avoid missing recent rows.