browserforensics
Back to all articles

Browser cache forensics: Chrome, Firefox and Safari

2026-06-21 · 4 min

The HTTP cache is the artifact people forget to clear. A user can wipe History and still leave behind a complete inventory of fetched URLs in the cache — every script, image and document the browser pulled, each with fetch timestamps. It proves a resource was on the wire even when the history row is gone, and the timestamps slot straight into a timeline.

Why the cache outlives history

Browsers treat the cache as performance data, not user data. "Clear browsing history" and the cache are separate toggles, and tools that wipe SQLite history rarely touch the cache directory. The result is a frequent mismatch: an empty urls table, a cache full of entries for the same sites. Each cache backend stores the request URL alongside fetch metadata, so even without the response body you recover what was requested and when.

Chrome / Edge: Simple Cache

Modern Chromium uses the Simple Cache backend on most platforms — one file per cached entry under the profile:

…\User Data\<profile>\Cache\Cache_Data\

Each entry file opens with a SimpleFileHeader. Critically, the header stores the entry key, which is the cached URL. Parse the directory and you get a URL inventory plus per-entry size, without decoding any bodies.

FieldMeaning
MagicIdentifies a Simple Cache entry
VersionHeader format version
Key lengthByte length of the URL key
KeyThe cached request URL

The older blockfile cache (data_0data_3 plus f_###### external files) is a different format and is not covered here.

Firefox: cache2

Firefox uses the cache2 backend, again one file per entry:

<profile>/cache2/entries/

Each file holds the response, followed by a metadata block appended at the end of the file. That trailer carries the request URL, a fetch count, and a set of timestamps:

MetadataMeaning
Key / URICached request URL
Fetch countNumber of times served from cache
Last fetchedUnix seconds
Last modifiedUnix seconds
ExpirationUnix seconds

The fetch count is useful on its own: it distinguishes a one-off load from a resource the user hit repeatedly. See browser timestamp formats for the unix-seconds conversions.

Safari: Cache.db

Safari does not scatter files — it uses a single SQLite database, Cache.db:

Table / columnMeaning
cfurl_cache_response.request_keyCached request URL
cfurl_cache_response.time_stampWhen the entry was stored
blob tablesThe cached response bodies

Because it is SQLite, you query it directly read-only — and the same WAL caveats apply, so grab Cache.db-wal and Cache.db-shm with it.

What the tool does

BrowserForensics groups an entire cache directory into a single artifact. Drop the Cache_Data or cache2/entries folder in and the hundreds of per-entry files collapse into one table of URLs and timestamps, ready to sort, filter and export.

Honest limits:

  • It recovers the URL and metadata inventory, not the cached response bodies.
  • It does not parse the legacy Chrome blockfile cache (data_# / f_*).

For most investigations the inventory is the point: the question is usually did this machine fetch that URL, and when, not can I rebuild the rendered page.

Using cache in an investigation

  • Corroborate cleared history. Cache URLs for a site whose history row is missing is a strong deletion signal.
  • Prove a fetch happened. The presence of an entry shows the resource was requested, independent of whether the user "visited" in the UI sense.
  • Feed the timeline. Fetch and store timestamps are timeline events — fold them in alongside visits and downloads when you build a browser activity timeline.

Always copy the whole cache directory, not a selection of files: the per-entry layout means a partial copy is a partial inventory.

Further reading