Safari
Safari Sessions
Overview
Safari records the state of all open windows and tabs when the browser is closed. This session data is stored in LastSession.plist and is used by Safari to restore the user's browsing state on the next launch. For forensic investigations, session data provides a snapshot of what the user was actively browsing at the time Safari was last closed -- a high-value artifact for understanding recent user activity.
Session data captures not only the URLs and titles of open tabs but also window-level metadata including which tab was selected (active), whether the window was a Private Browsing window, and unique identifiers for each window and tab.
File Locations
| File | Path | Format |
|---|---|---|
| Last session state | ~/Library/Safari/LastSession.plist | Binary Property List |
| Recently closed tabs | ~/Library/Safari/RecentlyClosedTabs.plist | Binary Property List |
| Cloud tabs | ~/Library/Safari/CloudTabs.db | SQLite |
| Tab groups | ~/Library/Safari/SafariTabs.db | SQLite |
The primary artifact is LastSession.plist. Additional session-related files provide supplementary context.
File Format
LastSession.plist is a binary property list with a structured hierarchy of session, windows, and tabs.
Plist Structure
Root (Dictionary)
SessionVersion (Integer)
SessionWindows (Array)
[0] (Dictionary) -- Window
WindowUUID (String)
IsPrivate (Boolean)
SelectedTabIndex (Integer)
TabStates (Array)
[0] (Dictionary) -- Tab
TabUUID (String)
TabURL (String)
TabTitle (String)
LastVisitTime (Date)
isAppInitiated (Boolean)
[1] (Dictionary)
...
[1] (Dictionary) -- Window
...
Window Fields
| Key | Type | Description |
|---|---|---|
WindowUUID | String | Unique identifier for the window |
IsPrivate | Boolean | Whether this is a Private Browsing window |
SelectedTabIndex | Integer | Index of the active/focused tab (0-based) |
TabStates | Array | Array of tab state dictionaries |
Tab Fields
| Key | Type | Description |
|---|---|---|
TabUUID | String | Unique identifier for the tab |
TabURL | String | Current URL loaded in the tab |
TabTitle | String | Page title displayed on the tab |
LastVisitTime | Date | Timestamp of the last visit to this tab's URL |
isAppInitiated | Boolean | Whether the tab was opened by the app (e.g., session restore) |
Additional Session Files
RecentlyClosedTabs.plist (macOS 10.13+): Records tabs that were recently closed, enabling Safari's "Reopen Last Closed Tab" feature. Structure is similar to tab entries in LastSession.plist.
CloudTabs.db (macOS 11.0+): SQLite database containing tabs synced via iCloud from the user's other Apple devices. Can reveal browsing activity on iPhones, iPads, and other Macs linked to the same Apple ID.
SafariTabs.db (macOS 12.0+): SQLite database for the Tab Groups feature, which allows users to organise tabs into named groups. Tab group names chosen by the user can be highly informative.
Key Fields for Analysis
TabURL: The current URL of each open tab. This reveals what the user was actively looking at when Safari closed.TabTitle: The page title provides context even when the URL is opaque (e.g., dynamically generated URLs or URLs with encoded parameters).SelectedTabIndex: Identifies which tab was in focus in each window. The selected tab represents what the user was most recently viewing in that window.IsPrivate: A value oftrueindicates a Private Browsing window. While Safari does not persist Private Browsing history, the session state may capture private window tab URLs if Safari was not cleanly closed.WindowUUID/TabUUID: Unique identifiers for correlation across artifacts and backup snapshots.isAppInitiated: Distinguishes between tabs opened by user action and tabs restored automatically by Safari's session restore feature. A value oftruetypically indicates the tab was part of a restored session rather than opened by the user in the current session.LastVisitTime: When available, provides a timestamp for the last navigation in each tab.
Timestamps
The LastVisitTime field is stored as a standard property list <date> value in ISO 8601 format. Not all tabs may have this field populated.
The modification time of LastSession.plist itself indicates when Safari was last closed (or when the session state was last saved).
Analysis Notes
- Active browsing snapshot:
LastSession.plistcaptures the exact state of the browser at the moment it was closed. This is particularly valuable when the user was in the middle of a task -- open tabs in email, document editing, research, or communication services reveal current activity. - Multiple windows: Users may have multiple windows open, each with its own set of tabs. The window array preserves all windows. Examine each window separately as they may represent different tasks or contexts.
- Private browsing detection: The
IsPrivateflag on windows reveals that the user had Private Browsing windows open. While the flag only appears in session data (not persisted history), its presence is evidence that Private Browsing was in use. - Tab count as indicator: An unusually large number of tabs may indicate research activity. The specific tabs open provide context for the research topic.
- Session restore artefact: When Safari restores a session after a crash or reboot, the
isAppInitiatedflag is set on restored tabs. This can help distinguish between tabs the user opened in the current session and those carried forward from a previous session. - Correlation with history: Cross-reference tab URLs with History.db to determine when each tab was first opened and how long it had been open.
- Cloud tabs: If
CloudTabs.dbexists, it can reveal tabs open on the user's other Apple devices, providing a broader picture of cross-device browsing activity.
Version Differences
| Version | Change |
|---|---|
| Safari 10-14 (macOS 10.12-10.15) | Basic session state with windows and tabs |
| Safari 13+ (macOS 10.13+) | RecentlyClosedTabs.plist introduced |
| Safari 15+ (macOS 11.0+) | CloudTabs.db for iCloud tab sync |
| Safari 15+ (macOS 12.0+) | SafariTabs.db for Tab Groups feature |
The LastSession.plist format has remained stable, with minor additions to per-tab metadata in newer versions.
Tool Support
macfor
The browser.safari plugin parses LastSession.plist and emits two record types:
browser_session_window: Window-level records with fieldswindow_index,window_uuid,is_private,selected_tab_index,tab_count, andsource_file.browser_session_tab: Tab-level records with fieldswindow_index,tab_index,tab_uuid,url,title,last_visit_time,is_app_initiated, andsource_file.
The raw plist file is also preserved in the evidence container.
Manual Analysis
# Convert to XML for inspection
plutil -convert xml1 -o - ~/Library/Safari/LastSession.plist
# Quick summary with Python
python3 -c "
import plistlib
with open('LastSession.plist', 'rb') as f:
session = plistlib.load(f)
windows = session.get('SessionWindows', [])
print(f'Session version: {session.get(\"SessionVersion\", \"unknown\")}')
print(f'Windows: {len(windows)}')
for i, window in enumerate(windows):
private = ' [PRIVATE]' if window.get('IsPrivate', False) else ''
tabs = window.get('TabStates', [])
selected = window.get('SelectedTabIndex', -1)
print(f'\nWindow {i}{private} ({len(tabs)} tabs, selected: {selected})')
for j, tab in enumerate(tabs):
marker = ' <-- ACTIVE' if j == selected else ''
url = tab.get('TabURL', 'about:blank')
title = tab.get('TabTitle', '')
print(f' [{j}] {title[:60]}')
print(f' {url[:80]}{marker}')
"
References
- Apple Property List Documentation
- SANS FOR518: Mac and iOS Forensic Analysis