Browser, email and cloud sync · Lesson 3 of 6
Cache, private browsing and what survives
11 min read
Lessons 4.1 and 4.2 read the history databases. This lesson covers the browser cache, which keeps copies of what was actually delivered, and private browsing, which removes the history and the cache but not the traces the rest of Windows keeps. The examiner's job is to know which traces remain, where to find them, and how far they let a finding go.
What the cache holds and why it matters
A browser stores copies of pages, images, scripts, style sheets and other downloaded content so that it can show them again without fetching them. Each cache entry keeps the key (essentially the URL), the content itself, and the server's response headers, such as Date (when the server sent the response), Last-Modified, Content-Type, Content-Length and ETag, plus times written by the browser on the local clock. This gives the examiner three things that the history database does not: the content the user saw, proof that the content reached this browser profile, and a timestamp from the server's clock.
The Date header is written by the web server, which is normally synchronized, so it is a useful external clock; a response served from a CDN or proxy cache keeps its original Date, and an Age header then shows how old it is. Compare it with the local times of the same entry to measure device clock skew (Lesson 3.5). Last-Modified gives a lower bound: the content cannot have been delivered before it last changed on the server.
Chromium cache
Chrome keeps its HTTP cache in %LOCALAPPDATA%\Google\Chrome\User Data\Default\Cache\Cache_Data; Edge uses the same layout under %LOCALAPPDATA%\Microsoft\Edge\User Data\<profile>. The on-disk format varies by platform and version. Recent Chrome on Windows uses the blockfile format in Cache_Data:
| File | Content |
|---|---|
index | Hash table of entry addresses; magic 0xC103CAC3 |
data_0 | 36-byte blocks: rankings, the least-recently-used list with last-used times |
data_1 | 256-byte blocks: entry records with key, creation time and stream addresses, and small data |
data_2, data_3 | 1,024-byte and 4,096-byte blocks: headers and bodies up to 16 KB |
f_XXXXXX | Separate files for streams larger than 16 KB, such as f_0001a3 |
Each entry has stream 0 (the parsed HTTP response information, including the headers) and stream 1 (the body, often still gzip- or Brotli-compressed as sent). Chromium stores times as microseconds since 1601-01-01 UTC. On Android, Linux, ChromeOS and macOS, Chromium uses the simple cache format by default instead: one file per entry named <16 hex digits>_0, with optional _1 and _s files and an index-dir folder.
Since Chrome 86 the HTTP cache is partitioned by site, so keys may begin with a prefix such as 1/0/_dk_ followed by the top-level site that loaded the resource. That prefix tells you which page a third-party image or script was loaded for.
Two neighboring folders are often confused with the cache. Code Cache (subfolders js and wasm) holds compiled JavaScript and WebAssembly keyed by script URL: it shows that a site's scripts ran, not what was displayed. GPUCache holds compiled graphics shaders and has little evidential value.
Firefox cache2
Firefox 32 and later use the cache2 format in the local (not roaming) profile: %LOCALAPPDATA%\Mozilla\Firefox\Profiles\<profile>\cache2\entries. Each entry is one file, named with the 40-hex-digit SHA-1 hash of its key. The file holds the content first, then the metadata: chunk hashes, a header (version, fetch count, last fetched, last modified, frecency, expiration time, key size, flags), the key ending with the URL (preceded by short flags such as a,:), and named elements such as request-method and response-head, which contains the full response headers. The last 4 bytes are a big-endian offset to the start of the metadata, which equals the content length. Header times are 32-bit Unix seconds, big-endian. cache2\index summarizes all entries (hashes, frecency, flags) and does not contain URLs.
Worked example: reading a cache2 entry
An entry file is 15,240 bytes long. Its last 4 bytes are 00 00 3A 98 = 0x3A98 = 15,000, so bytes 0 to 14,999 are the cached content (they begin 89 50 4E 47, a PNG) and the metadata starts at offset 15,000. The last-fetched field reads 69 B5 60 85 = 1,773,494,405 seconds since 1970-01-01 = 2026-03-14T13:20:05Z. The response-head element contains Date: Sat, 14 Mar 2026 13:20:03 GMT. The local clock and the server agree within 2 seconds, which fits normal transfer time, so no skew correction is needed for this period.
Tools and limits
Free examples: NirSoft ChromeCacheView and MozillaCacheView list URL, content type, server time and last-modified time and export the content; Plaso has chrome_cache and firefox_cache2 parsers; Hindsight parses Chromium cache with history. Whatever the tool, open one entry by hand and confirm the times.
A cache is bounded. Browsers size it from settings or free disk space and evict the least recently used entries; responses marked Cache-Control: no-store, common on banking and login pages, are never written; and the user can clear the cache. Absence of a cache entry is not proof that a page was not visited.
Private browsing
Chrome Incognito, Edge InPrivate and Firefox Private Browsing all work the same way in principle. The browser does not write history, the download list, form data or search entries; cookies and site data live in memory and are discarded when the last private window closes; and the HTTP cache is kept in memory instead of Cache_Data or cache2. All three keep files downloaded in a private window and bookmarks (favorites) created in it, because those are stored outside the private session. Private mode protects against the next user of the profile, not against the operating system, the network or the sites visited.
The traces that survive therefore lie outside the browser's own databases:
| Trace | Survives private browsing? | Where |
|---|---|---|
| Visits, cookies, form data | No | Not written to History, Cookies or places.sqlite |
| HTTP cache | No (memory only) | Not written to Cache_Data or cache2 |
| Downloaded file | Yes | Download folder; $MFT and $UsnJrnl (Module 1) |
| Zone.Identifier ADS | Yes; Chrome Incognito omits the URL | Stream on the downloaded file (Lesson 1.4) |
| Bookmark created | Yes | Bookmarks file or places.sqlite |
| Browser execution | Yes, execution only | Prefetch, BAM (Lesson 2.3) |
| Network bytes per application | Yes, hourly totals | SRUM SRUDB.dat (Lesson 2.8) |
| Opened download | Yes | LNK files and Jump Lists (Lesson 2.4) |
| DNS names resolved | Until TTL expiry or reboot | DNS client cache in memory |
| URLs and page fragments | Possibly | RAM, pagefile.sys, hiberfil.sys (Module 5) |
| Connections | Yes, off the host | Proxy, firewall, DNS server and router logs |
| Account activity | Yes, if the user signed in | The online account's own records (Lesson 4.5) |
Points to apply precisely:
- Zone.Identifier. For a download in a normal window, Chromium on Windows 10 and 11 writes
HostUrlandReferrerUrl. For an Incognito download it does not pass the URL: the stream keepsZoneId=3, butHostUrlis the placeholderabout:internetandReferrerUrlis absent. Confirm the behavior of the version in your case with a test download. - Prefetch and BAM prove that
chrome.exeorfirefox.exeran, not that a private window was used. Prefetch does not record command-line arguments, so a switch such as--incognitoappears only where command lines are logged, for example Security event 4688 with command-line auditing enabled; a window opened with Ctrl+Shift+N in a running browser is not started with that switch at all. - DNS client cache. On a live system,
ipconfig /displaydnslists names the Windows DNS client resolved; it is volatile and gone after a reboot. A browser that resolves names itself, such as Chrome with its built-in resolver enabled, can bypass this cache, and one using DNS over HTTPS also bypasses the local DNS server's logs. - Network logs usually show host names, not full URLs: for HTTPS, a non-intercepting proxy logs the host and port of the
CONNECTrequest, not the path.
Cleared history is not private browsing
Clearing history deletes rows that were written; private browsing never writes them. The difference matters because deleted rows can survive. In generic SQLite a deleted row lands in free space within a page or in a freelist page until reused or vacuumed, but Chromium and Firefox build SQLite with secure delete on, which overwrites deleted content with zeros in the main file. Copies may still remain in the rollback journal (History-journal in Chromium) or the write-ahead log (places.sqlite-wal in Firefox), in Volume Shadow Copies, and in the $UsnJrnl records of cache files deleted at the time of clearing. SRUM and Prefetch are not touched by the browser's clear function at all.
Wording a finding from side traces
When only side traces exist, state each source and its limit, and do not name a private window as fact unless something shows it. Suitable wording: "The traces are consistent with browsing to transfer.example.com in a private window; the browser history itself has no record of that site." Then list the alternatives you checked: another browser or profile, cleared history, or a different device.
Worked example: a receipt without history
A Windows 11 triage collection from a different case, for user lferraz, shows:
- Chrome
History: no visit or download fortransfer.example.com. The earliest visit in the database is 2026-04-21T15:02:41Z. C:\Users\lferraz\Downloads\upload-receipt.pdf, $SI created 2026-04-21T13:41:07Z, with Zone.IdentifierZoneId=3,ReferrerUrl=https://transfer.example.com/upload/done,HostUrl=https://transfer.example.com/r/8f3a/upload-receipt.pdf.- SRUM Network Data Usage for
chrome.exe, userlferraz, interval ending 14:00:00Z (previous row 13:00:00Z): BytesSent 734,003,200, BytesRecvd 9,437,184. Cache_Dataholds onlyindexand newdata_0todata_3files with no entries, created 2026-04-21T15:01:58Z.
Arithmetic. 734,003,200 ÷ 1,048,576 = 700 MiB sent and 9,437,184 ÷ 1,048,576 = 9 MiB received between 13:00:00Z and 14:00:00Z, a ratio of about 78:1 that fits an upload. The download at 13:41:07Z falls inside that interval.
What can be concluded. A file was saved at 13:41:07Z from a URL on transfer.example.com, after a page on that site (/upload/done). chrome.exe, under lferraz, sent about 700 MiB in the same hour.
What the private-browsing hypothesis must explain. The real HostUrl argues against a Chrome Incognito download, which would have recorded about:internet. A cache recreated at 15:01:58Z and a history that starts at 15:02:41Z fit clearing of browsing data shortly before 15:02, not private browsing, which leaves the normal cache untouched. Next steps: carve History-journal, unallocated space and shadow copies for older History pages, check $UsnJrnl for deleted f_ files around 15:01Z, and examine Edge and other Chrome profiles, because another Chromium browser could have written the same stream.
What cannot be concluded. Neither SRUM nor Zone.Identifier says what was uploaded or that the 700 MiB went to transfer.example.com; SRUM has no destination. Proxy or DNS logs from the network are needed for that link.
Exam focus: Expect to read a cache entry's URL,Dateheader or content type, or to compute a Firefox cache2 metadata offset from the last 4 bytes. Be ready to choose which artifacts survive private browsing, to report aHostUrlor SRUM byte count, and to recognize that a realHostUrlon a Chromium download does not fit Incognito. Questions may contrast cleared history (copies possibly recoverable) with private browsing (nothing written).
Key points
- Cache entries hold content, the URL key and server response headers; the
Dateheader is an external clock for skew checks. - Chrome on Windows uses blockfile
Cache_Data(index,data_0todata_3,f_files); Firefox 32+ uses onecache2\entriesfile per entry with metadata after the content. - Caches are size-limited, skip
no-storeresponses and can be cleared, so a missing entry proves nothing. - Private browsing does not write history, cookies, form data or disk cache, but downloads, bookmarks, Prefetch, BAM, SRUM, LNK files, memory and network logs remain.
- Chrome Incognito downloads carry
ZoneId=3withHostUrl=about:internet; a real URL points elsewhere. - Cleared history is zero-filled in the main database by secure delete but can survive in journals, WAL files and shadow copies; private browsing leaves nothing there.