WhatsApp Desktop
WhatsApp Desktop
Overview
WhatsApp Desktop on macOS stores its complete chat history as a plaintext, unencrypted SQLite database in a Group Container directory (~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatStorage.sqlite). Any user-level process can read this database without Full Disk Access, without root privileges, and without any decryption keys. This is the defining forensic characteristic of WhatsApp Desktop: a messaging platform that users widely perceive as end-to-end encrypted exposes its entire local message history to any investigator with filesystem access.
This stands in direct contrast to Apple iMessage, whose database at ~/Library/Messages/chat.db requires Full Disk Access (TCC-protected). WhatsApp has no equivalent protection on the macOS Catalyst app.
WhatsApp Desktop has shipped in two distinct variants. The current native Catalyst app (net.whatsapp.WhatsApp, distributed via the Mac App Store) uses Apple's Core Data framework and stores messages in a Core Data SQLite database with ZWA-prefixed entity names. The legacy Electron app (desktop.WhatsApp, deprecated in 2024) stored data in Chromium IndexedDB/LevelDB format. This article covers the native Catalyst app. Legacy Electron storage is noted where relevant for historical cases.
The secondary data source is the iCloud backup located at ~/Library/Mobile Documents/57T9237FN3~net~whatsapp~WhatsApp/Accounts/<phone>/backup/. This directory contains AES-encrypted .enc database files (requiring the user's E2E backup key to decrypt) alongside unencrypted .tar archives containing media, documents, and thumbnails. Investigators can access the tar archives without any decryption keys.
The Critical Finding: Plaintext Group Container
The native WhatsApp Catalyst app is distributed as a sandboxed Mac App Store application, but it uses a shared App Group container (group.net.whatsapp.WhatsApp.shared) rather than its private sandbox container. App Group containers in ~/Library/Group Containers/ are accessible to any process running as the same user — they are specifically designed for inter-process data sharing. WhatsApp uses this mechanism to share the chat database with its notification extension (net.whatsapp.WhatsApp.ServiceExtension), but as a consequence, any user-level process on the system can read ChatStorage.sqlite without any TCC permission prompt or Full Disk Access.
No Full Disk Access Required
Unlike Apple Messages (chat.db), iMessage attachments, or Mail databases, WhatsApp's ChatStorage.sqlite requires only standard user-level read permissions. A collection tool running as the logged-in user can read the full chat history without any TCC approval or elevated privileges. This has been documented by security researcher Mysk (@mysk_co) in July 2024.
Forensic implication: WhatsApp's end-to-end encryption protects messages in transit. It does not protect messages at rest on the local macOS filesystem. An investigator with physical access to the device, a forensic image, or a live acquisition running as the user has direct access to the complete plaintext message history.
File Locations
Native Catalyst App (Primary)
| Artifact | Path | Format | Notes |
|---|---|---|---|
| Live chat database | ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatStorage.sqlite | SQLite (plaintext) | Primary forensic artifact — no encryption |
| Chat database WAL | ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatStorage.sqlite-wal | SQLite WAL | Uncommitted transactions — always collect |
| Chat database SHM | ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatStorage.sqlite-shm | SQLite SHM | Shared memory file |
| Full-text search index | ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatSearch.sqlite | SQLite FTS | May retain text from deleted messages |
| Search WAL | ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatSearch.sqlite-wal | SQLite WAL |
iCloud Backup (Secondary)
The iCloud backup path encodes both the App Team ID and bundle ID: 57T9237FN3~net~whatsapp~WhatsApp. Account directories are named with the full phone number including country code (e.g., 14155551234).
| Artifact | Path | Format | Notes |
|---|---|---|---|
| Backup metadata | ~/Library/Mobile Documents/57T9237FN3~net~whatsapp~WhatsApp/Accounts/<phone>/backup/Backup.plist | Plist | Unencrypted — size inventory, date, version |
| Chat database (encrypted) | …/backup/ChatStorage.sqlite.enc | AES encrypted | Requires E2E backup key |
| Call history (encrypted) | …/backup/CallHistory.sqlite.enc | AES encrypted | Requires E2E backup key |
| Key-value store (encrypted) | …/backup/BackedUpKeyValue.sqlite.enc | AES encrypted | Cryptographic keys and account data |
| Search index (encrypted) | …/backup/ChatSearch.sqlite.enc | AES encrypted | Requires E2E backup key |
| Extended chat data (encrypted) | …/backup/ExtChatDatabase.sqlite.enc | AES encrypted | |
| Media archive | …/backup/Media.tar | Tar | Unencrypted — images and attachments |
| Video archive | …/backup/Video.tar | Tar | Unencrypted — video files |
| Document archive | …/backup/Document.tar | Tar | Unencrypted — shared documents |
| GIF archive | …/backup/GIFs.tar | Tar | Unencrypted |
| Sticker archive | …/backup/Stickers.tar | Tar | Unencrypted |
| Thumbnail archive | …/backup/Thumbnail.tar | Tar | Unencrypted — image thumbnails |
Unencrypted Tar Archives
The .tar archives in the iCloud backup directory are not encrypted, regardless of whether the user has enabled end-to-end encrypted backups. Media files, documents, and thumbnails can be extracted from these archives without any decryption keys.
Extension Containers
| Artifact | Path | Notes |
|---|---|---|
| Notification media | ~/Library/Containers/net.whatsapp.WhatsApp.ServiceExtension/Data/tmp/documents/ | JPEG thumbnails for incoming message notifications |
| Service extension preferences | ~/Library/Containers/net.whatsapp.WhatsApp.ServiceExtension/Data/Library/Preferences/net.whatsapp.WhatsApp.ServiceExtension.plist |
Legacy Electron App Paths (Deprecated)
| Artifact | Path | Format |
|---|---|---|
| Message data (IndexedDB) | ~/Library/Containers/desktop.WhatsApp/Data/Library/Application Support/WhatsApp/IndexedDB/ | LevelDB |
| Chromium cache | ~/Library/Containers/desktop.WhatsApp/Data/Library/Application Support/WhatsApp/Cache/ | Chromium cache |
| Application log | ~/Library/Containers/desktop.WhatsApp/Data/Library/Application Support/WhatsApp/main-process.log | Text |
Application Variants
| Property | Native Catalyst (Current) | Electron (Deprecated) |
|---|---|---|
| Bundle ID | net.whatsapp.WhatsApp | desktop.WhatsApp |
| Distribution | Mac App Store | Direct download (.dmg) |
| macOS minimum | 11.0 | 10.15 |
| Storage format | Core Data SQLite | Chromium IndexedDB / LevelDB |
| Database location | ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ | ~/Library/Containers/desktop.WhatsApp/ |
| Encryption | None (plaintext) | None (plaintext) |
| iCloud backup | Yes | No |
| Status | Active (2024–present) | Deprecated (2024) |
WhatsApp JID Format
WhatsApp uses XMPP-derived Jabber IDs (JIDs) to identify all entities. JIDs appear throughout the database in ZFROMJID, ZTOJID, ZCONTACTJID, ZMEMBERJID, and ZRECEIPTJID columns.
| JID Format | Entity Type | Example |
|---|---|---|
<phone>@s.whatsapp.net | Individual contact | 14155551234@s.whatsapp.net |
<id>@g.us | Group chat | 120363123456789012@g.us |
<phone>@broadcast | Broadcast list | 14155551234@broadcast |
status@broadcast | Status updates | status@broadcast |
The phone number in @s.whatsapp.net JIDs is the full E.164 international number without the leading + sign. 14155551234 represents +1-415-555-1234. Phone numbers can be extracted directly from JIDs without any additional lookup, enabling identity attribution across the dataset.
Account directories in the iCloud backup path follow the same format — a directory named 14155551234 belongs to that phone number.
Core Data Schema Overview
The native Catalyst app uses Apple Core Data with the following primary entities (tables). All table names carry the ZWA prefix from Core Data code generation.
| Table | Purpose |
|---|---|
ZWAMESSAGE | All messages — text, media references, delivery status |
ZWACHATSESSION | Conversation threads — 1:1, group, broadcast |
ZWAMEDIAITEM | Media attachment metadata — paths, URLs, MIME types, dimensions, geolocation |
ZWAGROUPINFO | Group metadata — name, description, creator |
ZWAGROUPMEMBER | Group membership — JIDs, admin roles |
ZWAMESSAGEINFO | Per-recipient delivery and read receipts |
ZWAPROFILEPUSHNAME | Contact display names as set by the contact |
ZWAPROFILEPICTUREITEM | Contact avatar metadata |
ZWAMESSAGEDATAITEM | Extended message data for vCards and structured content |
ZWAGROUPMEMBERSCHANGE | Group membership change event log |
ZWAVCARDMENTION | Contacts mentioned within messages |
Z_PRIMARYKEY | Core Data internal — entity type registry and record counts |
Z_METADATA | Core Data internal — model version hash |
See Chat Database for complete table schemas and SQL queries.
Timestamp Format
All timestamp columns in the native Catalyst app use the Apple Core Data epoch: seconds (floating-point) since January 1, 2001, 00:00:00 UTC. This is the same epoch used by iMessage, FaceTime, Apple Contacts, and all other Core Data applications.
Conversion formula:
unix_timestamp = core_data_timestamp + 978307200
Example:
Core Data value: 764553600.0
+ 978307200
= Unix timestamp: 1742860800
= 2025-03-24 00:00:00 UTC
SQL conversion:
-- Convert a Core Data timestamp to ISO 8601 in SQLite
SELECT datetime(ZMESSAGEDATE + 978307200, 'unixepoch') AS message_time
FROM ZWAMESSAGE;
Zero values in timestamp columns indicate the timestamp was not set. Null values indicate the column was not applicable (e.g., ZSENTDATE is null for received messages).
Key Artifacts
Chat Database (ChatStorage.sqlite)
The primary forensic artifact. Contains the complete local message history in plaintext — message text, sender JIDs, delivery status, media references, group membership, and read receipts. Accessible without encryption or Full Disk Access. See Chat Database for schema documentation.
Full-Text Search Index (ChatSearch.sqlite)
An FTS (Full-Text Search) database that WhatsApp maintains alongside the main database. The search index may retain indexed text from messages that have since been deleted from ChatStorage.sqlite, making it a potential source for deleted message recovery.
iCloud Backup Directory
A second copy of the chat data synced to iCloud. The SQLite databases are AES-encrypted and require the user's end-to-end backup key to decrypt. However, the .tar archives containing media files are unencrypted and accessible immediately. The Backup.plist metadata file provides size inventory and backup timestamps. See iCloud Backup.
Notification Extension Media
The ServiceExtension container may hold JPEG thumbnail images for incoming message notifications. These can provide visual evidence of media shared in conversations even when the main chat database is unavailable.
macOS Version Support
| macOS Version | Native Catalyst | Electron (Legacy) | Notes |
|---|---|---|---|
| 10.15 Catalina | Not supported | Full | Electron only era |
| 11.0 Big Sur | Full | Full (deprecated later) | Catalyst requires macOS 11+ |
| 12.0 Monterey | Full | Available | |
| 13.0 Ventura | Full | Deprecated | WhatsApp began deprecation process |
| 14.0 Sonoma | Full | End-of-life | Users prompted to switch to native |
| 15.0 Sequoia | Full | Not supported | Native app only |
The Core Data schema is driven by WhatsApp application releases, not macOS versions. Schema column additions occur with WhatsApp app updates and may add columns for features such as message editing, view-once media, disappearing messages, or WhatsApp Channels.
Forensic Analysis Notes
- Phone number attribution is direct: JIDs encode full E.164 phone numbers. Cross-reference
@s.whatsapp.netJIDs with Contacts (contacts.addressbook) to resolve names without requiring a WhatsApp account lookup. - Delivery receipts are per-recipient:
ZWAMESSAGEINFOstores a separate row for each group member who received or read the message. For outgoing group messages,ZMESSAGESTATUSon theZWAMESSAGErow reflects aggregate delivery state, whileZWAMESSAGEINFOprovides individual recipient confirmation. - Forwarded messages: The
ZISFORWARDEDflag onZWAMESSAGEindicates a message was forwarded from another conversation. TheZFORWARDCOUNTcolumn tracks how many times the message has been forwarded. This is significant for disinformation or data exfiltration investigations. - Starred messages:
ZSTARRED = 1marks messages the user explicitly saved. Starred messages often indicate content the user considered important. - Archived chats:
ZWACHATSESSION.ZARCHIVED = 1indicates the user archived a conversation. Archived chats are hidden from the default view but remain in the database. - Disappearing messages:
ZWACHATSESSION.ZDISAPPEARINGMESSAGEDURATIONsets the auto-delete timer. Individual messages already deleted by the timer are removed from the database — but the conversation record remains and theZMESSAGECOUNTERstill reflects the historical total. - WAL mode: ChatStorage.sqlite operates with SQLite WAL mode. Always collect
ChatStorage.sqlite-walandChatStorage.sqlite-shmalongside the main file to capture all committed transactions. - Record counts from Z_PRIMARYKEY: The Core Data
Z_PRIMARYKEYtable'sZ_MAXcolumn reflects the highest primary key value ever assigned for each entity type. This acts as a lower bound on the total number of messages or sessions ever created, regardless of how many remain in the active tables.
Deleted Message Recovery
SQLite does not immediately overwrite freed pages when rows are deleted. WhatsApp message text, JIDs, and other string data may persist in SQLite free pages after deletion. The ChatSearch.sqlite FTS index may also retain indexed text from deleted messages. See Deleted Messages for recovery techniques.
Tool Support
| Tool | Support Level |
|---|---|
| macfor | Full collection: messages, conversations, iCloud backup enumeration, media tar extraction, deleted message recovery |
| AXIOM | WhatsApp Desktop support |
| Cellebrite | WhatsApp Desktop support |
| DB Browser for SQLite | Manual analysis — open ChatStorage.sqlite directly |
| sqlite3 CLI | Direct query access |