惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
The GitHub Blog
The GitHub Blog
美团技术团队
Know Your Adversary
Know Your Adversary
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Register - Security
The Register - Security
Stack Overflow Blog
Stack Overflow Blog
Attack and Defense Labs
Attack and Defense Labs
G
Google Developers Blog
I
InfoQ
博客园 - 司徒正美
T
Troy Hunt's Blog
Google DeepMind News
Google DeepMind News
J
Java Code Geeks
MongoDB | Blog
MongoDB | Blog
博客园 - 聂微东
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
S
Security Affairs
M
MIT News - Artificial intelligence
Simon Willison's Weblog
Simon Willison's Weblog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tailwind CSS Blog
量子位
Vercel News
Vercel News
月光博客
月光博客
V
Vulnerabilities – Threatpost
N
News and Events Feed by Topic
Hugging Face - Blog
Hugging Face - Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LangChain Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
L
LINUX DO - 最新话题
F
Full Disclosure
The Hacker News
The Hacker News
Hacker News: Ask HN
Hacker News: Ask HN
T
Tor Project blog
A
Arctic Wolf
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Forbes - Security
Forbes - Security
IT之家
IT之家
Apple Machine Learning Research
Apple Machine Learning Research
B
Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Y
Y Combinator Blog
GbyAI
GbyAI
B
Blog RSS Feed
V
Visual Studio Blog
T
The Blog of Author Tim Ferriss
F
Fortinet All Blogs

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Apple Fixes the iOS Bug That Cops Used to Extract Deleted Chat Messages From iPhones
佐藤玲 · 2026-04-24 · via DEV Community

Apple Fixes the iOS Bug That Cops Used to Extract Deleted Chat Messages From iPhones

For years, a quiet vulnerability sat buried inside iOS — one that most users never knew existed, but that law enforcement agencies around the world quietly relied upon. Apple has now patched the bug, closing a forensic backdoor that allowed investigators (and, theoretically, any attacker with physical device access) to recover deleted iMessage conversations and chat data that users believed was gone forever.

If you build apps, handle user data, or care at all about mobile security architecture, this story has layers worth unpacking.


What Was the Bug, Exactly?

The vulnerability centered on how iOS handled SQLite database write-ahead logging (WAL) for iMessage and other chat apps that rely on Apple's native data persistence stack.

When a user deletes a message in iMessage, iOS marks the record for deletion in the SQLite database. Under normal circumstances, the next database checkpoint operation would overwrite those records. The bug: in certain conditions, iOS failed to properly execute that checkpoint, leaving recoverable data in the WAL file — a temporary transaction log that SQLite uses to stage writes before committing them to the main database file.

Digital forensics tools used by law enforcement — including Cellebrite UFED and similar physical extraction platforms — were specifically designed to extract and parse these residual WAL files, giving investigators access to messages the user had intentionally deleted.

A Quick Primer on SQLite WAL Mode

For those unfamiliar, here's how WAL mode works under the hood:

-- Enable WAL mode on a SQLite database
PRAGMA journal_mode=WAL;

-- When you DELETE a record...
DELETE FROM messages WHERE rowid = 42;

-- The deletion is written to the WAL file first
-- It is NOT immediately removed from the main database
-- A CHECKPOINT is required to sync WAL changes to the main .db file
PRAGMA wal_checkpoint(TRUNCATE);

Enter fullscreen mode Exit fullscreen mode

In normal operation, SQLite checkpoints automatically. But iOS's implementation introduced a race condition and edge cases where checkpointing was skipped or deferred — especially after an ungraceful shutdown, a crash, or when storage I/O was under pressure.

The result: a ghost copy of "deleted" records lingered in -wal files on-disk, completely outside the user's control.


How Cops Actually Used This

Law enforcement agencies that obtained physical access to a locked or unlocked iPhone could use forensic extraction tools to pull a full file system image. Inside that image:

/private/var/mobile/Library/SMS/sms.db        ← Main iMessage database
/private/var/mobile/Library/SMS/sms.db-wal    ← Write-ahead log (the problem)
/private/var/mobile/Library/SMS/sms.db-shm    ← Shared memory index

Enter fullscreen mode Exit fullscreen mode

By parsing sms.db-wal independently, forensic analysts could reconstruct deleted message rows — including message content, timestamps, sender/receiver metadata, and in some cases, attachment references.

This wasn't a theoretical attack. Court documents across multiple jurisdictions cite iMessage extraction as a source of evidence, sometimes explicitly referencing data that defendants had deleted.


What Apple's Fix Actually Does

Apple's patch — rolled out in a recent iOS point release — addresses the bug at the persistence layer by:

  1. Forcing synchronous WAL checkpoints after message deletion events, ensuring the WAL file is flushed and truncated promptly.
  2. Encrypting WAL files with per-session keys that are discarded after a successful checkpoint, making residual data cryptographically unreadable even if the file persists temporarily on disk.
  3. Tightening the lifecycle management of SQLite connections in the Messages framework so that database handles are closed cleanly, triggering automatic checkpoint behavior.

This is a meaningful defense-in-depth improvement — not just a band-aid.


What This Means for Developers

If you're building iOS apps that store sensitive user data, this bug is a case study in how storage-layer assumptions can silently undermine application-level security.

Lesson 1: Never Assume Delete Means Delete

At the SQLite level, deletion is logical, not physical, until a vacuum or checkpoint occurs. If your app stores sensitive data:

// Don't just DELETE and assume the data is gone
let deleteQuery = "DELETE FROM sensitive_data WHERE id = ?"

// Also force a WAL checkpoint
let checkpointQuery = "PRAGMA wal_checkpoint(TRUNCATE);"

// And consider running VACUUM for full physical removal
let vacuumQuery = "VACUUM;"

Enter fullscreen mode Exit fullscreen mode

Note: VACUUM rebuilds the entire database file and can be expensive — use it judiciously, perhaps on a background thread after bulk deletions.

Lesson 2: Encrypt Sensitive Columns, Not Just the Database File

Relying solely on full-disk encryption (which is what iOS Data Protection provides) doesn't help when the device is in an After First Unlock (AFU) state — which covers the vast majority of forensic extractions since most people don't power off their phones.

For truly sensitive data, consider column-level encryption:

import CryptoKit

func encryptMessageContent(_ plaintext: String, key: SymmetricKey) throws -> Data {
    let data = Data(plaintext.utf8)
    let sealedBox = try AES.GCM.seal(data, using: key)
    return sealedBox.combined!
}

func decryptMessageContent(_ ciphertext: Data, key: SymmetricKey) throws -> String {
    let sealedBox = try AES.GCM.SealedBox(combined: ciphertext)
    let decryptedData = try AES.GCM.open(sealedBox, using: key)
    return String(data: decryptedData, encoding: .utf8)!
}

Enter fullscreen mode Exit fullscreen mode

Even if WAL files are extracted, encrypted column values are useless without the key — and if you tie the key to Secure Enclave-backed credentials, it never leaves the device in extractable form.

Lesson 3: Use iOS Data Protection Classes Correctly

Apple provides tiered data protection that controls when files are accessible:

// When creating your SQLite database file, set the protection class
let fileManager = FileManager.default
let dbURL = getDocumentsDirectory().appendingPathComponent("app.db")

try fileManager.setAttributes(
    [.protectionKey: FileProtectionType.completeUnlessOpen],
    ofItemAtPath: dbURL.path
)

// CompleteUnlessOpen means the file is only accessible when the device
// is unlocked OR the file is already open
// Use .complete for maximum protection (file locked when screen locks)

Enter fullscreen mode Exit fullscreen mode

For the highest sensitivity data, FileProtectionType.complete ensures the encryption key is discarded the moment the screen locks — making cold extraction significantly harder.


The Broader Privacy and Civil Liberties Angle

It would be incomplete to discuss this purely as a technical bug. The existence and use of this vulnerability raises real questions:

  • Should Apple have fixed this sooner? The WAL behavior has been documented in forensic literature for years. Whether Apple's delay was negligence, deliberate, or the result of competing engineering priorities is unclear.
  • Does fixing it obstruct legitimate law enforcement? This is the perennial tension in device security. Apple has consistently maintained that it does not build intentional backdoors — but unintentional ones that go unpatched for extended periods occupy an uncomfortable gray zone.
  • What about third-party apps? Apps like WhatsApp, Signal, and Telegram that implement their own SQLite-backed storage may have the same WAL exposure. Signal, notably, already implements its own encrypted database layer (Signal Protocol SQLCipher) that addresses this class of attack. Other apps may not.

As a developer, these aren't abstract policy questions — they're architecture decisions you make when you choose how to store user data.


How to Check if Your App Is Vulnerable

If you're using Core Data or direct SQLite in your iOS app, run this quick audit:

# On a simulator or jailbroken test device, check if WAL files persist after deletion
# Look for .db-wal files in your app's container
find ~/Library/Developer/CoreSimulator -name "*.db-wal" 2>/dev/null

# If you find them, open the WAL file directly with sqlite3
sqlite3 path/to/your/app.db
.mode column
.headers on
PRAGMA journal_mode;
-- If output is 'wal', you're in WAL mode
PRAGMA wal_checkpoint(FULL);
-- Check if checkpoint succeeds and WAL size drops to 0

Enter fullscreen mode Exit fullscreen mode

Also audit your app for:

  • [ ] Are you closing SQLite connections explicitly?
  • [ ] Are you handling app backgrounding/termination with proper DB cleanup?
  • [ ] Do you store sensitive plaintext in any database column?
  • [ ] Are your database files using the highest appropriate Data Protection class?

Update Your Devices — Now

For end users reading this: update to the latest iOS version. Apple fixes security vulnerabilities in point releases, and this one matters. If you're on an older device that no longer receives updates, consider what data you store in iMessage and whether alternatives with stronger security models (Signal, for instance) are appropriate for sensitive communications.

For developers: audit your data persistence layer against the checklist above. The fact that Apple fixes these issues doesn't mean your app inherits the protection — if you're rolling your own SQLite stack, you need to implement these safeguards yourself.


Final Thoughts

The cops-used-to-extract-deleted-messages story is attention-grabbing, but the underlying technical reality is what should concern every developer building privacy-sensitive apps: storage primitives don't give you privacy guarantees by default. WAL files, undo logs, temp files, and OS-level caches all create windows where "deleted" data isn't actually gone.

Apple's fix is a step forward. But the lesson for the dev community is to build as if no OS-level fix is coming — encrypt sensitive data, force proper cleanup, and never trust that a DELETE statement is the end of the story.


If you found this breakdown useful, follow me here on DEV for more deep-dives into mobile security, iOS internals, and privacy engineering. Drop your questions or war stories in the comments — I read everything.

→ Want this kind of analysis in your inbox before it hits social? Subscribe to the newsletter linked in my profile.