Disappearing Messages
Technical specification for automatic message expiration and secure deletion in Zentalk.
Overview
Disappearing messages provide an additional layer of privacy by automatically deleting messages after a specified time period. This feature ensures that sensitive conversations do not persist indefinitely on devices, reducing the risk of data exposure from device theft, unauthorized access, or forensic analysis.
Privacy Benefits
| Benefit | Description |
|---|---|
| Reduced data exposure | Messages automatically removed after expiration |
| Limited forensic surface | Less recoverable data on device storage |
| Conversation ephemerality | Mimics in-person conversation impermanence |
| Storage management | Automatic cleanup of old messages |
| Relationship privacy | Ex-partners, former colleagues cannot review old messages |
Available Timer Options
| Timer Duration | Use Case |
|---|---|
| 1 hour | Highly sensitive, time-critical information |
| 24 hours | Day-to-day sensitive conversations |
| 7 days | General privacy-conscious messaging |
| 30 days | Long-form discussions with eventual cleanup |
| Custom (1 min - 365 days) | User-defined expiration requirements |
Timer Configuration
Timer Settings Payload:
┌─────────────────────────────────────────┐
│ Timer Mode (1 byte) │
│ 0x00 = Disabled │
│ 0x01 = After Send │
│ 0x02 = After Read │
├─────────────────────────────────────────┤
│ Duration (4 bytes, uint32) │
│ Value in seconds │
│ Range: 60 - 31536000 (1 min - 1 year) │
├─────────────────────────────────────────┤
│ Timestamp (8 bytes) │
│ Unix timestamp of setting change │
└─────────────────────────────────────────┘Timer Mechanism
Zentalk implements disappearing messages with client-side timer enforcement. The server has no knowledge of timer settings or expiration times, ensuring that message lifecycle remains under user control.
Timer Start Modes
| Mode | Timer Starts | Use Case |
|---|---|---|
| After Send | When message leaves sender device | Guaranteed maximum lifetime |
| After Read | When recipient opens message | Ensures recipient sees message |
Client-Side Timer Implementation
Timer Lifecycle:
1. Sender sets disappearing timer for conversation
timer_setting = { mode: AFTER_READ, duration: 86400 }
2. Message created with embedded timer:
message.timer = encrypt(timer_setting, session_key)
message.send_timestamp = current_time()
3. Recipient receives and decrypts message:
timer_setting = decrypt(message.timer, session_key)
4. Timer activation:
IF timer_setting.mode == AFTER_SEND:
expiration = message.send_timestamp + timer_setting.duration
ELSE IF timer_setting.mode == AFTER_READ:
expiration = read_timestamp + timer_setting.duration
5. Client schedules deletion:
schedule_deletion(message_id, expiration)Timer Synchronization Between Devices
All linked devices maintain synchronized timer state through the multi-device sync protocol:
| Sync Event | Action |
|---|---|
| Timer setting changed | Broadcast encrypted setting to all devices |
| Message read | Sync read receipt with timestamp |
| Message deleted | Sync deletion confirmation |
| Device reconnect | Reconcile timer states |
Timer Sync Protocol:
Device A (sender):
1. Sets timer for conversation with Bob
2. Encrypts timer setting with self-sync key
3. Broadcasts to Device B, Device C (own devices)
Device B receives:
1. Decrypts timer setting
2. Updates local conversation settings
3. Applies to future messages
4. Sends ACK to Device A
Conflict Resolution:
- Latest timestamp wins
- Vector clock prevents race conditionsExpiration Enforcement
When a message timer expires, Zentalk performs secure deletion to minimize data recovery possibilities.
Deletion Trigger Process
| Step | Action | Verification |
|---|---|---|
| 1 | Timer expires | Client-side scheduler fires |
| 2 | Verify message exists | Check local database |
| 3 | Delete message content | Secure overwrite |
| 4 | Delete associated media | Remove from cache and storage |
| 5 | Delete metadata | Remove timestamps, sender info |
| 6 | Sync deletion | Notify other devices |
| 7 | Confirm deletion | Update conversation view |
What Gets Deleted
| Data Type | Deletion Scope | Method |
|---|---|---|
| Message text | Full content | Secure overwrite |
| Media files | Original + thumbnails | Secure overwrite |
| Metadata | Timestamps, message ID | Database row removal |
| Read receipts | Associated receipts | Cascade delete |
| Reactions | Emoji reactions | Cascade delete |
| Reply references | Quote previews | Nullify or delete |
| Search index | Message tokens | Index removal |
Secure Deletion Implementation
Secure Deletion Process:
1. Identify target data locations:
- IndexedDB message store
- File system cache (media)
- In-memory buffers
- Search index entries
2. For each storage location:
Database Records:
- Overwrite content with random bytes
- Update record with null values
- Delete record from table
- Trigger index rebuild
File System:
- Overwrite file with random data (3 passes)
- Truncate file to zero length
- Unlink file from filesystem
- Request secure delete from OS (where available)
Memory:
- Zero memory buffers
- Release memory to allocator
- Request garbage collection
3. Verification:
- Attempt to read deleted data
- Confirm retrieval fails
- Log deletion completionPlatform-Specific Secure Deletion
| Platform | Secure Delete Method | Limitations |
|---|---|---|
| iOS | NSFileManager with NSFileProtectionComplete | SSD wear leveling |
| Android | File.delete() + explicit overwrite | Flash storage copies |
| Desktop (Electron) | Node.js unlink + overwrite | SSD block mapping |
| Web | IndexedDB delete | Browser storage management |
Encryption of Timer Settings
Timer settings are encrypted within the message payload, preventing server-side manipulation or observation.
Timer Value Encryption
| Component | Encryption | Key Source |
|---|---|---|
| Timer mode | AES-256-GCM | Session key |
| Duration value | AES-256-GCM | Session key |
| Timestamp | AES-256-GCM | Session key |
Encrypted Timer Structure
Message Payload with Timer:
┌─────────────────────────────────────────┐
│ Header │
├─────────────────────────────────────────┤
│ Encrypted Content │
│ ├── Message Text │
│ ├── Timer Settings (encrypted) │
│ │ ├── Mode (1 byte) │
│ │ ├── Duration (4 bytes) │
│ │ └── Set Timestamp (8 bytes) │
│ └── Media References │
├─────────────────────────────────────────┤
│ Authentication Tag (16 bytes) │
└─────────────────────────────────────────┘
The timer settings are:
1. Included in encrypted payload
2. Covered by AEAD authentication
3. Cannot be read by server
4. Cannot be modified without detectionServer Cannot Modify Timer
| Attack Vector | Prevention Mechanism |
|---|---|
| Server reads timer | Timer encrypted with session key |
| Server extends timer | AEAD tag verification fails |
| Server shortens timer | AEAD tag verification fails |
| Server removes timer | AEAD tag verification fails |
| Replay with old timer | Sequence number mismatch |
MAC Authentication
Timer Authentication:
1. Timer included in AEAD associated data:
AD = message_id || sender_id || sequence_num || timer_blob
2. Encryption:
ciphertext, tag = AES-256-GCM(
key = session_key,
nonce = unique_nonce,
plaintext = message_content || timer_settings,
associated_data = AD
)
3. Recipient verification:
- Decrypt with session key
- Verify tag matches
- Any modification invalidates tag
- Reject message if verification failsMulti-Device Behavior
Disappearing messages must behave consistently across all linked devices while handling offline scenarios.
Timer Sync Across Devices
| Scenario | Behavior |
|---|---|
| Timer set on Device A | Synced to B, C via encrypted channel |
| Message received on Device A first | A starts timer, syncs to B, C |
| Timer expires on Device A | Deletion synced to B, C |
| Devices have clock skew | Use sender timestamp as reference |
Offline Device Handling
Offline Expiration Scenario:
Timeline:
T+0: Message sent to Alice (timer: 24h)
T+1h: Alice reads on Phone (timer starts)
T+2h: Alice's Tablet goes offline
T+25h: Timer expires on Phone
T+25h: Phone deletes message
T+48h: Tablet comes online
Tablet Reconnection:
1. Tablet syncs with Phone
2. Receives deletion sync record
3. Verifies message should be deleted
4. Performs catch-up deletion
5. Confirms deletion to sync serviceCatch-Up Deletion on Reconnect
| Step | Action | Data |
|---|---|---|
| 1 | Device reconnects | Establish sync session |
| 2 | Fetch deletion log | Message IDs + deletion timestamps |
| 3 | Compare local state | Identify messages to delete |
| 4 | Execute deletions | Secure delete each message |
| 5 | Confirm sync | Update deletion log |
| 6 | Prune deletion log | Remove entries older than 30 days |
Deletion Log Structure
Deletion Log Entry:
┌─────────────────────────────────────────┐
│ Message ID (32 bytes) │
├─────────────────────────────────────────┤
│ Conversation ID (32 bytes) │
├─────────────────────────────────────────┤
│ Deletion Timestamp (8 bytes) │
├─────────────────────────────────────────┤
│ Deletion Reason (1 byte) │
│ 0x01 = Timer expired │
│ 0x02 = User deleted │
│ 0x03 = Admin deleted (groups) │
├─────────────────────────────────────────┤
│ Signature (64 bytes) │
└─────────────────────────────────────────┘
Log entries are:
- Encrypted with device sync key
- Retained for 30 days
- Used for offline device catch-up
- Pruned after all devices confirmGroup Chat Disappearing Messages
Group chats support disappearing messages with additional considerations for multi-party settings.
Per-Group Timer Settings
| Setting Level | Scope | Persistence |
|---|---|---|
| Group default | All messages in group | Until changed |
| Per-message override | Single message | Message lifetime |
| Member preference | Display only | Local to device |
Permission Model
| Role | Can View Timer | Can Change Timer | Can Override |
|---|---|---|---|
| Owner | Yes | Yes | Yes |
| Admin | Yes | Yes | Configurable |
| Member | Yes | No (default) | No |
| Guest | Yes | No | No |
Admin-Only Timer Control
Group Timer Change Protocol:
1. Admin initiates timer change:
new_timer = { mode: AFTER_READ, duration: 86400 }
2. Create setting update message:
update = {
type: GROUP_SETTING_CHANGE,
setting: DISAPPEARING_TIMER,
value: new_timer,
admin_signature: sign(admin_key, update_payload)
}
3. Distribute via Sender Keys:
- Encrypt with admin's Sender Key
- Broadcast to group
- All members receive and verify
4. Member verification:
- Verify admin signature
- Verify admin has permission
- Apply new setting locally
- Future messages use new timerNew Member Joins After Timer Set
| Scenario | Behavior |
|---|---|
| Member joins group with timer | Receives current timer setting |
| Existing messages | Not accessible (forward secrecy) |
| New messages | Subject to group timer |
| Timer changed after join | Receives update via group sync |
New Member Timer Handling:
1. New member receives group state:
group_state = {
members: [...],
settings: {
disappearing_timer: { mode: AFTER_READ, duration: 3600 }
},
sender_keys: [...]
}
2. Member stores timer setting locally
3. For each new message received:
- Extract timer from encrypted payload
- Verify matches group setting
- Schedule deletion accordingly
4. For messages sent:
- Embed group timer in message
- Encrypt with Sender Key
- Other members honor sender's timerMedia and Attachments
Media files require special handling for disappearing messages due to their distributed storage.
Media Chunk Deletion
| Storage Location | Deletion Method | Timing |
|---|---|---|
| Local device cache | Secure overwrite | On timer expiry |
| Mesh storage nodes | Deletion request | Propagated async |
| CDN cache (if used) | TTL expiration | Best effort |
| Recipient devices | Secure overwrite | Synced deletion |
Media Deletion Process
Media Disappearing Flow:
1. Original upload:
- Media chunked and encrypted
- Chunks distributed to mesh nodes
- Chunk IDs stored in message
2. Timer expires:
- Delete local cached copy
- Send deletion request to mesh
- Request propagates to storage nodes
- Nodes mark chunks for deletion
3. Mesh deletion:
- Storage nodes receive deletion request
- Verify request signature (from sender)
- Mark chunks as deleted
- Actual deletion on next garbage collection
4. Verification:
- Attempt to fetch chunks fails
- 404 response from mesh nodes
- Deletion confirmedThumbnail Deletion
| Thumbnail Type | Storage | Deletion |
|---|---|---|
| Message preview | Local database | With message |
| Gallery cache | File system | On timer expiry |
| Notification preview | OS notification system | Best effort |
| Link preview | Local cache | With message |
Cached Preview Cleanup
Preview Cleanup Process:
1. Identify all cached previews:
- Image thumbnails (various sizes)
- Video thumbnails (first frame)
- Audio waveforms
- Document previews
- Link previews with images
2. For each preview type:
- Locate cache directory
- Find files matching message ID
- Secure delete each file
- Update cache index
3. Platform-specific cleanup:
- iOS: Clear NSCache entries
- Android: Clear Glide/Picasso cache
- Desktop: Clear Electron cache directory
- Web: Clear Cache API entriesBackup Implications
Disappearing messages interact with the backup system in specific ways to maintain privacy guarantees.
Backup Exclusion
| Data Type | Included in Backup | Reason |
|---|---|---|
| Active messages (no timer) | Yes | Normal backup |
| Messages with active timer | No | Would defeat purpose |
| Expired messages | No | Already deleted |
| Timer settings | Yes | Restore conversation settings |
| Deletion log | No | Transient sync data |
Backup Timing Considerations
Backup and Disappearing Messages:
Scenario 1: Message expires before backup
T+0: Message received (timer: 1h)
T+1h: Message expires, deleted
T+24h: Daily backup runs
Result: Message not in backup (correct)
Scenario 2: Message expires after backup
T+0: Message received (timer: 48h)
T+24h: Daily backup runs
T+48h: Message expires, deleted
Result: Message in backup (problematic)
Mitigation:
- Backup process checks timer expiration
- Messages with timer ≤ backup_interval excluded
- Backup metadata includes "disappearing excluded" flagPre-Expiration Backup Handling
| Scenario | System Behavior |
|---|---|
| Backup made before expiration | Message excluded from backup |
| Restore from backup | Disappearing messages not restored |
| Timer setting restored | Applied to new messages only |
| Backup conflict | Timer setting from latest backup wins |
Recovery Limitations
Recovery Behavior:
1. User loses device
2. Restores from backup
3. Recovery includes:
- Non-disappearing messages: Restored
- Disappearing message content: Not restored
- Conversation exists: Yes
- Timer settings: Restored
- Message history gap: Visible
4. Recipient's perspective:
- Their copy also expired
- No authoritative record exists
- Message effectively erasedLimitations and Caveats
While disappearing messages provide enhanced privacy, users should understand their limitations.
Security Limitations
| Limitation | Description | Mitigation |
|---|---|---|
| Screenshots | Recipients can capture screen | Screenshot detection (partial) |
| Photos of screen | Cannot prevent external camera | User education |
| Copy/paste | Text can be copied before deletion | UI restrictions (partial) |
| Memory forensics | RAM may contain traces | Memory zeroing on delete |
| Storage forensics | Deleted data may be recoverable | Secure overwrite |
| Backup leakage | External backup tools | Exclude message files |
| Malicious clients | Modified app ignores timers | Cannot fully prevent |
Screenshot Considerations
Screenshot Handling:
Detection (where available):
- iOS: UIApplicationUserDidTakeScreenshotNotification
- Android: FileObserver on screenshot directory
- Desktop: Limited detection capability
- Web: No reliable detection
Response options:
1. Notify sender of screenshot
2. Display warning to recipient
3. No prevention possible
User should understand:
- Screenshots cannot be prevented
- Notifications are best-effort
- Privacy depends on recipient trustCannot Prevent Recipient Saving
| Save Method | Prevention Possible | Detection Possible |
|---|---|---|
| Screenshot | No | Partial |
| Screen recording | No | Partial (iOS/Android) |
| External photo | No | No |
| Copy text | Partial (disable) | No |
| Forward message | Yes (can disable) | N/A |
| Export chat | Yes (respect timer) | N/A |
Forensic Security Assessment
Forensic Recovery Difficulty:
High Difficulty (secure):
- Encrypted message content
- Overwritten file content
- Zeroed memory buffers
Medium Difficulty:
- File system metadata
- Database transaction logs
- OS-level caches
Low Difficulty (vulnerable):
- Unencrypted backups
- Screenshots in photo library
- Notification content logs
- Third-party keyboard logs
Assessment:
Disappearing messages provide privacy against:
- Casual inspection
- Relationship partners
- Stolen device (if locked)
Disappearing messages do NOT provide protection against:
- Determined forensic analysis
- Nation-state adversaries
- Recipient with intent to save
- Malicious app modificationsTrust Model
| Trust Assumption | Reality |
|---|---|
| Recipient will not save | Cannot be enforced |
| App is unmodified | User could use modified client |
| Device is secure | May be compromised |
| OS respects deletion | May have hidden caches |
| Network is secure | Messages already E2EE |
Implementation Recommendations
Timer Selection Guidelines
| Communication Type | Recommended Timer |
|---|---|
| Sensitive credentials | 1 hour or less |
| Personal discussions | 24 hours |
| Work conversations | 7 days |
| General privacy | 30 days |
| Legal/compliance | Consult requirements |
User Education Points
| Topic | Key Message |
|---|---|
| False sense of security | Disappearing is not forensically secure |
| Recipient trust | Feature requires trusting recipient |
| Backup implications | Messages will not be recoverable |
| Multi-device sync | All devices delete together |
| Group chats | All members see timer setting |
Related Documentation
- Protocol Specification - E2EE implementation details
- Multi-Device Support - Device synchronization
- Group Chat Protocol - Sender Keys and group management
- Architecture - System design overview
- Threat Model - Security assumptions and limitations