Chrome
Chrome Local Storage
Overview
Chrome implements the Web Storage API's localStorage using Google's LevelDB key-value store rather than SQLite. Each Chrome profile has a single LevelDB database that stores all Local Storage data for all origins, with keys that encode both the web origin and the storage key name.
Local Storage can contain authentication tokens, user preferences, application state, cached data, and other web application data. Unlike cookies, Local Storage data does not expire automatically and is not sent with HTTP requests, making it a preferred location for persistent client-side data in modern web applications.
File Locations
| Path | Description |
|---|---|
~/Library/Application Support/Google/Chrome/{Profile}/Local Storage/leveldb/ | LevelDB database directory |
LevelDB Directory Structure
Local Storage/leveldb/
├── CURRENT # Points to the current MANIFEST file
├── LOCK # Lock file (indicates active use)
├── LOG # Recent operations log (text)
├── LOG.old # Previous operations log
├── MANIFEST-000001 # Database manifest (SSTable metadata)
├── 000003.log # Write-ahead log (WAL) with uncommitted data
├── 000004.ldb # Sorted string table (SSTable) with committed data
└── 000005.ldb # Additional SSTable
Database Schema / File Format
LevelDB Overview
LevelDB is a log-structured merge tree (LSM) key-value store. Data is organized across:
- Write-ahead log (
.logfiles): Contains recent writes not yet compacted. May contain data not present in SSTables. - Sorted string tables (
.ldbfiles): Immutable, sorted key-value files. Older tables may contain deleted or overwritten values. - Manifest (
MANIFEST-*): Tracks which SSTables are current and their key ranges. - CURRENT: A text file pointing to the active manifest.
Key Format
Local Storage keys in LevelDB follow a specific binary format:
_<origin>\x00<key>
- The key begins with an underscore (
_) prefix byte. - The origin (e.g.,
https://example.com) follows immediately. - A null byte (
\x00) separates the origin from the storage key name. - The storage key name follows the null separator.
Example: _https://github.com\x00user-preferences stores the user-preferences Local Storage key for the https://github.com origin.
Value Encoding
Values are typically encoded as UTF-16LE (Little Endian) strings. Binary detection is performed by checking for non-printable characters after decoding.
Key Fields for Analysis
- Origin: The web origin that stored the data (extracted from the key prefix). Reveals which sites store persistent data.
- Key: The storage key name. Application-specific names like
auth_token,session,user_data, orpreferencesindicate the type of data stored. - Value: The stored data. May be plain text, JSON, or binary data. Large JSON values often contain rich application state.
- Value size: The raw byte count of the value before decoding.
Forensically Interesting Keys
| Key Pattern | Potential Content |
|---|---|
*token*, *auth*, *session* | Authentication tokens and session identifiers |
*user*, *profile*, *account* | User identity information |
*preferences*, *settings* | Application configuration |
*cache*, *store*, *state* | Cached application data |
*history*, *recent* | In-application activity history |
*draft*, *unsaved* | Unsaved user input |
Timestamps
LevelDB itself does not store timestamps for individual entries. The file modification times of the .ldb and .log files provide approximate timeframes:
| File | Significance |
|---|---|
.log files | Modification time indicates when recent writes occurred |
.ldb files | Modification time indicates when compaction created the file |
LOG (text) | Contains timestamped operation logs from LevelDB |
Analysis Notes
- macfor copies the entire LevelDB directory for forensic preservation, then opens a read-only copy for parsing. This ensures the original data is not modified.
- The write-ahead log (
.logfiles) may contain data that was written but not yet compacted into SSTables. This can include recently stored or modified values. - Deleted keys may still be present in older SSTables as tombstone records. LevelDB does not immediately remove data; it is cleaned up during compaction.
- Values are truncated to 256 characters in macfor's parsed output (the
value_previewfield). The full value is preserved in the raw LevelDB files collected in the evidence container. - Value types are detected automatically:
jsonfor valid JSON strings,textfor printable text, andbinaryfor non-printable content. - The
LOCKfile indicates that Chrome had the database open. Its presence in collected evidence means Chrome was running or did not shut down cleanly. - Session Storage (
Session Storage/directory) uses the same LevelDB format but is intended for session-scoped data that should be cleared when the tab closes. In practice, data may persist.
Version Differences
The LevelDB Local Storage format has been consistent across Chrome versions. Chrome has explored alternatives (e.g., migrating to a different storage backend) but the LevelDB format remains in use as of Chrome 130+.
Tool Support
| Tool | Capability |
|---|---|
| macfor | Copies raw LevelDB directory, parses key-value entries with origin attribution, detects value types |
| leveldb-dump | Command-line tool for dumping LevelDB contents |
| Hindsight | Includes Local Storage parsing in Chrome analysis |
| ccl_chrome_indexeddb | Python library for Chrome LevelDB parsing |