Skip to content

User activityNetworkFile access

Browser Profiles on Linux: Firefox and Chrome History

Firefox and Chrome/Chromium profile databases on Linux, including snap and Flatpak paths: history, downloads, epochs and how to query them offline.

Location
~/.mozilla/firefox/<profile>/places.sqlite
Proves
Which sites a user visited, what they downloaded and searched for, and when
Timestamps
Firefox PRTime (usec since 1970 UTC); Chrome/Chromium WebKit time (usec since 1601-01-01 UTC)
Access
Any user for own profile; root for other users
Retention
Chrome: visits expire after 90 days; Firefox: size-based expiration of old, low-frecency pages
Collection
UAC, Velociraptor, cp -a, tar

What it is

Browsers keep a per-user profile directory with SQLite databases and JSON files that record history, downloads, bookmarks, cookies, form data and session state. On Linux the layout is the same as on other platforms, but the profile location depends on how the browser was installed: distribution package, vendor package, snap or Flatpak. Missing the right directory is the most common reason browser evidence is "not found" on Ubuntu desktops, where Firefox and Chromium ship as snaps.

Where it lives

Browser / packagingProfile root
Firefox (deb/rpm or tarball)~/.mozilla/firefox/<profile>/
Firefox 147+ new installs~/.config/mozilla/firefox/<profile>/ (XDG layout; an existing ~/.mozilla keeps being used)
Firefox snap (Ubuntu default)~/snap/firefox/common/.mozilla/firefox/<profile>/
Firefox Flatpak~/.var/app/org.mozilla.firefox/.mozilla/firefox/<profile>/
Firefox cache~/.cache/mozilla/firefox/<profile>/; snap: ~/snap/firefox/common/.cache/mozilla/firefox/
Google Chrome~/.config/google-chrome/ (-beta, -unstable for other channels)
Chromium (deb/rpm)~/.config/chromium/
Chromium snap~/snap/chromium/common/chromium/
Chrome / Chromium Flatpak~/.var/app/com.google.Chrome/config/google-chrome/, ~/.var/app/org.chromium.Chromium/config/chromium/
Edge, Brave~/.config/microsoft-edge/, ~/.config/BraveSoftware/Brave-Browser/
Chromium-family cache~/.cache/google-chrome/, ~/.cache/chromium/ and so on

$XDG_CONFIG_HOME or $CHROME_CONFIG_HOME can move Chrome's root. Inside a Chromium-family root, profiles are Default, Profile 1, Profile 2...; Local State describes them. Firefox lists its profiles in profiles.ini and installs.ini next to the profile folders.

These paths are the same on Debian/Ubuntu, RHEL/Fedora and other families; the packaging choice (snap on Ubuntu, Flatpak when installed from Flathub) is what changes them.

What it proves

  • Pages visited, how they were reached (typed, link, bookmark, redirect, download) and visit counts.
  • Files downloaded, from which URL and referrer, where they were saved and whether they were opened (Chrome).
  • Search terms typed into the address bar (Chrome keyword_search_terms).
  • Open tabs and windows at a point in time (session files).

It does not prove who was at the keyboard, and synced profiles can contain visits made on another device (Chrome visits carries originator fields for synced rows). Private/incognito browsing is not written to these databases.

Key fields

Firefox places.sqlite

Table.columnMeaning
moz_places.url, title, visit_count, typed, last_visit_date, frecencyOne row per URL
moz_historyvisits.place_id, visit_date, visit_type, from_visitOne row per visit; visit_type 1 link, 2 typed, 3 bookmark, 4 embed, 5/6 redirect, 7 download, 8 framed link, 9 reload
moz_bookmarks.fk, title, dateAdded, lastModifiedBookmarks (fk = moz_places.id)
moz_annos + moz_anno_attributes (downloads/destinationFileURI, downloads/metaData)Download target path and state

Other Firefox files: cookies.sqlite, formhistory.sqlite, favicons.sqlite, sessionstore.jsonlz4 and sessionstore-backups/recovery.jsonlz4 (LZ4-compressed JSON), extensions.json, prefs.js.

Chrome / Chromium History

Table.columnMeaning
urls.url, title, visit_count, typed_count, last_visit_time, hiddenOne row per URL
visits.url (= urls.id), visit_time, from_visit, transition, visit_durationOne row per visit; transition & 0xFF is the core type (0 link, 1 typed, 2 auto bookmark, 7 form submit, 8 reload...)
downloads.target_path, current_path, start_time, end_time, received_bytes, total_bytes, state, danger_type, opened, last_access_time, referrer, tab_url, mime_typeDownload records
downloads_url_chains.urlFull redirect chain of each download
keyword_search_terms.term, url_idSearch terms typed in the omnibox

Other Chromium files: Cookies, Web Data (autofill), Bookmarks (JSON), Preferences, Sessions/, Extensions/.

Timestamps

BrowserFormatSQLite conversion
FirefoxPRTime, microseconds since 1970-01-01 UTCdatetime(visit_date/1000000, 'unixepoch')
Firefox bookmarksPRTimedatetime(dateAdded/1000000, 'unixepoch')
Chrome/ChromiumMicroseconds since 1601-01-01 UTCdatetime(visit_time/1000000 - 11644473600, 'unixepoch')

All are UTC. visit_duration in Chrome is a duration in microseconds, not a timestamp.

Retention

  • Chrome/Chromium: history entries older than 90 days are expired automatically (kExpireDaysThreshold).
  • Firefox: no fixed age. Places expiration trims old, low-frecency pages when the database grows beyond an optimal size (capped at 75 MiB) or places.history.expiration.max_pages.
  • Users can clear history, set "clear on close", or browse privately. Deleted rows often survive in SQLite free pages and in -wal files until the database is vacuumed or checkpointed.

Collection

Close the browser or acquire from an image: live databases are locked and recent changes sit in the -wal or -journal file. Always copy the companions with each database.

UAC's files/browsers/* artifacts (in the full profile, not in ir_triage) cover Firefox, Chrome, Chromium, Edge, Brave, Opera and Vivaldi, including snap and Flatpak locations (the Chromium artifact covers only the snap and Flatpak paths, so copy a deb/rpm ~/.config/chromium yourself); caches are excluded by default (files/browsers/cache.yaml). Check your UAC version for the Firefox 147 ~/.config/mozilla/firefox path.

sudo ./uac -p full /mnt/usb/case42
# or targeted, from a read-only mount
cd /mnt/evidence
find home root -maxdepth 8 \( -name 'places.sqlite*' -o -name 'History' -o -name 'History-journal' \
  -o -name 'profiles.ini' -o -name 'Local State' -o -name '*.jsonlz4' \) -print0 | tar --null -T - -czf browsers.tgz

Parsing

  • Hindsight (obsidianforensics/hindsight) parses Chromium-family profiles and, with -b Firefox, Firefox history, cookies and form history, into XLSX, JSONL or SQLite output. Point -i at a copied profile directory, for example hindsight.py -i ./google-chrome/Default -o case42-chrome -f jsonl.
  • Plaso webhist preset includes sqlite/firefox_history, sqlite/firefox_downloads, sqlite/chrome_27_history, sqlite/chrome_66_cookies and cache parsers.
  • sqlite3 on copies:
-- Firefox visits
SELECT datetime(v.visit_date/1000000,'unixepoch') AS utc, v.visit_type, p.url, p.title
FROM moz_historyvisits v JOIN moz_places p ON p.id = v.place_id ORDER BY v.visit_date;

-- Chrome downloads
SELECT datetime(start_time/1000000-11644473600,'unixepoch') AS utc, target_path, tab_url, referrer, received_bytes, opened
FROM downloads ORDER BY start_time;

Firefox jsonlz4 files start with the magic mozLz40\0; strip the 8-byte magic and 4-byte size, then LZ4-block-decompress (for example with the Python lz4 package).

Investigator tips

  • On Ubuntu, check the snap paths first; a nearly empty ~/.mozilla next to a busy ~/snap/firefox is normal.
  • Tie downloads to the filesystem: target_path or downloads/destinationFileURI gives the path to check for inode times, and files in /tmp or /dev/shm (see tmp and shm).
  • Follow a file from download to use: download record, then recently-used.xbel for opening, then shell history for chmod +x or execution.
  • A root-owned or service-account browser profile on a server is unusual and worth explaining.
  • Run PRAGMA freelist_count; and carve free pages when history looks cleared.
  • Browsers keep cookies and saved credentials in these profiles; collect them only when in scope, and do not attempt to decrypt credentials.

See also