Firefox

Firefox Session Data

Overview

Firefox maintains session state in compressed JSONLZ4 files within the sessionstore-backups/ directory. These files record all open windows and tabs, per-tab navigation history, scroll positions, pinned tabs, container tab assignments, and recently closed tabs and windows. Firefox updates these files periodically (approximately every 15 seconds) and on browser shutdown, making them a near-real-time snapshot of the user's browsing state.

Session data is forensically valuable because it captures the user's active browsing context at the time of collection: what sites were open, which tab was active, full per-tab back/forward history, and recently closed content that may no longer appear in browsing history.

File Locations

FilePathDescription
Current session~/Library/Application Support/Firefox/Profiles/{profile}/sessionstore-backups/recovery.jsonlz4Active session (updated every ~15 seconds)
Session backup~/Library/Application Support/Firefox/Profiles/{profile}/sessionstore-backups/recovery.baklz4Backup of previous recovery file
Previous session~/Library/Application Support/Firefox/Profiles/{profile}/sessionstore-backups/previous.jsonlz4Session from the last browser shutdown
Legacy session~/Library/Application Support/Firefox/Profiles/{profile}/sessionstore.jsonlz4Older Firefox versions

All session files use the Mozilla JSONLZ4 compression format and must be decompressed before analysis.

File Format

JSONLZ4 Binary Structure

OffsetSizeDescription
08 bytesMagic header: mozLz40\x00 (hex: 6D 6F 7A 4C 7A 34 30 00)
84 bytesOriginal (decompressed) size, little-endian uint32
12N bytesLZ4 block-compressed data

Key implementation details:

  • This is LZ4 block format, not the more common LZ4 frame format. Standard LZ4 frame decompressors will fail.
  • The macfor collector caps decompressed output at 100 MB to prevent memory exhaustion.
  • The decompressed content is standard JSON.

Decompressed Session JSON Structure

{
  "windows": [
    {
      "tabs": [
        {
          "entries": [
            { "url": "https://example.com", "title": "Example" },
            { "url": "https://example.com/page2", "title": "Page 2" }
          ],
          "index": 2,
          "lastAccessed": 1706234567000,
          "pinned": false,
          "hidden": false,
          "userContextId": 0,
          "image": "https://example.com/favicon.ico"
        }
      ],
      "selected": 1,
      "width": 1440,
      "height": 900,
      "screenX": 0,
      "screenY": 25,
      "sizemode": "maximized",
      "_closedTabs": []
    }
  ],
  "selectedWindow": 1,
  "session": {
    "lastUpdate": 1706234567000,
    "startTime": 1706200000000,
    "recentCrashes": 0
  },
  "_closedWindows": []
}

Session Metadata

FieldDescription
session.lastUpdateWhen the session file was last written (Unix ms)
session.startTimeWhen the current session began (Unix ms)
session.recentCrashesNumber of recent session crashes
selectedWindowIndex of the currently focused window (1-indexed)

Window Fields

FieldDescription
tabsArray of open tabs in this window
selectedIndex of the active tab (1-indexed)
width / heightWindow dimensions in pixels
screenX / screenYWindow position on screen
sizemodeWindow state: normal, maximized, minimized, fullscreen
isPrivateTrue if this is a private browsing window
_closedTabsRecently closed tabs (recoverable)

Tab Fields

FieldDescription
entriesNavigation history entries (back/forward list)
indexCurrent position in entries array (1-indexed)
lastAccessedWhen the tab was last viewed (Unix ms)
pinnedWhether the tab is pinned
hiddenWhether the tab is hidden (e.g., by Tab Groups extensions)
userContextIdContainer tab ID (0 = default, 1+ = specific container)
scrollScroll position within the current page
imageTab favicon URL

Tab Entry Fields

FieldDescription
urlPage URL
titlePage title
referrerReferrer URL for this navigation
subframeWhether this is a subframe entry
persistWhether the entry persists across session restores

Key Fields for Analysis

FieldForensic Significance
Tab entries arrayFull per-tab navigation history (back button sequence)
Tab indexCurrent page in the entries sequence
lastAccessedWhen the user last viewed each tab
pinnedPinned tabs indicate frequently used, persistent sites
userContextIdIdentifies container tab usage (separate identities)
_closedTabsRecently closed tabs -- content the user dismissed
_closedWindowsRecently closed windows
isPrivateIdentifies private browsing windows (if session data captures them)
session.recentCrashesNon-zero values indicate browser instability

Timestamps

Session file timestamps use Unix milliseconds (milliseconds since 1970-01-01 UTC).

lastAccessed = 1706234567000
Unix seconds = 1706234567000 / 1000 = 1706234567
Result = 2024-01-25T22:22:47Z

The recovery.jsonlz4 file's filesystem modification time also indicates when the session was last saved.

Analysis Notes

Reconstructing Active Browsing State

The session file captures a snapshot of what the user was doing:

  1. Which tabs were open: Each window's tabs array.
  2. Which tab was active: window.selected (1-indexed).
  3. What the user was looking at: The entries[index-1] of the selected tab.
  4. How they got there: The full entries array for each tab shows the navigation sequence.

Per-Tab Navigation History

Each tab's entries array is a complete back/forward history. The index field (1-indexed) indicates the current page. Entries before index are the back-button history; entries after are forward-button history (pages the user navigated back from).

For example, if a tab has 15 entries and index = 12, the user:

  • Navigated through 12 pages (entries 1-12).
  • Navigated back 3 times from later pages (entries 13-15 are in the forward history).
  • Is currently viewing entry 12.

Recently Closed Tabs

The _closedTabs array within each window contains tabs the user closed during the current session. This is a circular buffer with a limited capacity (typically 25 entries). Closed tabs include:

  • The full navigation history of the closed tab.
  • The time the tab was closed.
  • The tab's position and attributes.

Container Tab Analysis

Non-zero userContextId values indicate the user was using Firefox container tabs:

userContextIdTypical Container
0Default (no container)
1Personal
2Work
3Banking
4Shopping
5+Custom containers

Container tabs maintain separate cookie jars, so the same site in different containers represents different logged-in identities.

Session File Precedence

When analysing, prioritise files in this order:

  1. recovery.jsonlz4: Most recent session state (updated every ~15 seconds while Firefox is running).
  2. recovery.baklz4: Backup of the previous recovery file (one update cycle behind).
  3. previous.jsonlz4: Session from the last clean browser shutdown.

If recovery.jsonlz4 is missing but previous.jsonlz4 exists, the browser may have crashed or been forcefully terminated.

Crash Detection

  • session.recentCrashes > 0: The browser crashed recently.
  • Presence of recovery.jsonlz4 without previous.jsonlz4: Possible abnormal shutdown.
  • Very old session.lastUpdate: Session file was not updated before shutdown.

Private Browsing Windows

Windows with isPrivate: true occasionally appear in session data, particularly in crash recovery scenarios. Private browsing windows are not normally persisted, so their presence indicates the session file was written during an unexpected shutdown while a private window was open.

Version Differences

VersionChange
Firefox 56+JSONLZ4 format for session files (replaced JSON + gzip)
Firefox 57+_closedTabs and _closedWindows arrays for undo close
Firefox 72+userContextId for container tabs (Multi-Account Containers)

The JSONLZ4 session format has been consistent across all supported Firefox versions (78+). The internal JSON schema evolves gradually with new optional fields.

Tool Support

ToolCapability
macforFull JSONLZ4 decompression, window/tab extraction, container context parsing (Pro module)
lz4jsoncatCommand-line JSONLZ4 decompressor (part of mozilla-lz4 tools)
mozlz4-editWeb-based JSONLZ4 editor/decompressor
Python lz4 + custom scriptDecompress with 8-byte magic header handling
AXIOMAutomated Firefox session extraction
jqJSON processing after decompression

Manual Decompression (Python)

import lz4.block
import json

with open("recovery.jsonlz4", "rb") as f:
    magic = f.read(8)
    assert magic == b"mozLz40\x00"
    size = int.from_bytes(f.read(4), "little")
    data = lz4.block.decompress(f.read(), uncompressed_size=size)
    session = json.loads(data)

References

Previous
Extensions