The SMS That Kills Your Phone: A 5-Byte Prayer for Your Android’s Demise

The SMS That Kills Your Phone: A 5-Byte Prayer for Your Android’s Demise

A single malformed WAP Push SMS crashes com.android.phone on Android, dropping emergency calls and bricking devices. Zero-click, silent, and terrifying.

The SMS That Kills Your Phone: A 5-Byte Prayer for Your Android’s Demise

There’s a special kind of horror in a vulnerability that requires zero interaction from the victim. No malicious link to tap. No sketchy APK to sideload. No permission prompt to approve. Just a phone sitting on a table, minding its own business, and a single SMS that turns it into a brick.

Meet the “SMS of Death”, a working proof-of-concept that exploits an unchecked cast in Android’s telephony stack to remotely crash com.android.phone, drop active calls (including emergency calls), and in its most destructive form, drive a normal user to factory reset their device just to get it working again.

The scariest part? It’s already patched. The October 2026 Android security update fixes it. But if you’re on an older patch level, and a staggering number of Android devices always are, this attack still works.

One Cast, Five Bytes, Zero Clicks

The vulnerability lives in WapPushOverSms.decodeWapPdu(), a function in Android’s telephony framework that processes WAP Push messages delivered over SMS. WAP Push is a legacy protocol used for things like carrier provisioning and OTA configuration. It arrives as a data SMS on port 2948, gets routed to com.android.phone, and is processed without ever surfacing in the user’s message inbox.

Here’s where the magic happens. The code reads the WSP header length as a uintvar, a variable-length integer format that can encode values up to 32 bits. The value comes back as a long. Then this happens:

// WapPushOverSms.java:217  header length read as long, cast with no bounds check
int headerLength = (int) pduDecoder.getValue32();
    ...
// WapPushOverSms.java:244  the cast value is used as an array size
byte[] header = new byte[headerLength];

A 5-byte uintvar of 88 80 80 80 00 decodes to 0x80000000. Cast to a signed 32-bit int, that’s -2147483648. Allocating new byte[-2147483648] throws an uncaught NegativeArraySizeException on the telephony main thread, killing com.android.phone:

E AndroidRuntime: FATAL EXCEPTION: main
E AndroidRuntime: Process: com.android.phone
E AndroidRuntime: java.lang.NegativeArraySizeException: -2147483648
E AndroidRuntime:   at ...WapPushOverSms.decodeWapPdu(WapPushOverSms.java:244)
E AndroidRuntime:   at ...WapPushOverSms.dispatchWapPdu(WapPushOverSms.java:339)
E AndroidRuntime:   at ...InboundSmsHandler.processMessagePart(InboundSmsHandler.java:1169)
E AndroidRuntime:   at ...InboundSmsHandler$DeliveringState.processMessage(InboundSmsHandler.java:627)

The message is delivered as a data SMS and never shown to the user. There’s nothing in the inbox. The victim never sees the sender’s number. The phone just… dies.

Not Just a Crash, A Persistent Denial of Service

A crash of the telephony process would be bad enough. But the attacker gets more value for their money here. The malformed message doesn’t just crash the phone once, it becomes a persistent resident evil.

Here’s the chain of misery:

  • Zero-click. The victim does nothing.
  • Silent. Nothing appears in Messages, the attacker’s number is never shown.
  • Calls drop, including emergency calls. Active voice calls terminate with DisconnectCause CS_DEATH as the process restarts.
  • Telephony blackout. 1-2 seconds of no service per message while com.android.phone restarts.
  • Carrier redelivery amplifies it. Unacknowledged messages are re-sent by the carrier, re-crashing the phone. In testing, a single message caused intermittent outages for up to a week.
  • ~20 messages render the device unusable for an extended period.
  • Persistent denial of service. The malformed message stays queued and is retried on every boot, so the phone can crash on startup until the poison message is cleared.

The team behind the proof-of-concept tested it across multiple makes and models, Pixel 9 on April 2026 firmware, various Samsung Galaxy and A-series devices, with a 100% reproduction rate.

The Recovery: ADB, a Computer, and a Prayer

If you’re a power user, there’s a non-destructive recovery path. It requires ADB, a computer, and a brief window of opportunity between boot and crash. The poison messages sit in the pending inbound queue (content://sms/raw) and are retried on every boot. Android’s RescueParty escalates the situation, rebooting the device into recovery roughly every 90 seconds. A contributor documented a recovery method in GitHub issue #2 that deletes just those rows:

# while sys.boot_completed == 1: find the WAP Push rows (destination_port=134020), note the address
adb shell content query --uri content://sms/raw --projection _id:destination_port:date:deleted
# let the shell edit SMS storage, delete only those rows, then reset the permission
adb shell cmd appops set com.android.shell WRITE_SMS allow
adb shell "content delete --uri content://sms/raw --where \"address=''\""
adb shell cmd appops set com.android.shell WRITE_SMS default
# last resort, erases ALL SMS/MMS and APN settings:
adb shell pm clear com.android.providers.telephony

But for a non-technical user mid-loop, this is out of reach. They’re staring at a recovery screen with a “wipe data” option. Most people will just tap it. That’s the exact shape of a “Destructive Remote DoS” in Google’s VRP rules.

The Regulatory Kafka Trap

Here’s where things get properly Kafkaesque. Dropping calls isn’t just an inconvenience when one of those calls is to emergency services. Under Australia’s Telecommunications (Emergency Call Service) Determination, administered by the ACMA, carriers are required to identify mobile phones that cannot reach Triple Zero, help the customer move to a working device, and stop providing service to the affected handset. Telstra states plainly that it is required to block phones that can no longer call 000.

So the regulatory remedy for a phone that can’t reach emergency services is to cut it off the network, not to patch the OS. An attacker who can remotely induce that condition can, in effect, get the victim’s own device barred from carrier service until it’s updated.

The framework was tightened in 2024 following the 3G shutdown, which left some phones able to make ordinary calls but unable to reach emergency services, the same functional state this vulnerability produces. The regulation exists precisely because loss of emergency-call access is considered a public-safety failure. This bug manufactures that failure on demand.

What Google Actually Shipped

The fix Google shipped is instructive. The reporter provided a simple bounds check:

long rawHeaderLen = pduDecoder.getValue32();
if (rawHeaderLen < 0 || rawHeaderLen > pdu.length) {
    result.statusCode = Intents.RESULT_SMS_GENERIC_ERROR;
    return result;
}
int headerLength = (int) rawHeaderLen;

But on 15 June 2026, an Android engineer authored commit 735d967, “Fix remote DoS in decodeWapPdu”, which shipped in the October 2026 security release. Rather than validate the length, it widens the caught exception to swallow the crash and deletes the triggering message so it can’t re-crash on carrier redelivery or boot:

// WapPushOverSms.java: widen the catch to cover NegativeArraySizeException
- } catch (ArrayIndexOutOfBoundsException aie) {
+ } catch (RuntimeException e) {

// InboundSmsHandler.java: a failed decode now deletes the poison message
+ try { success = processMessagePart(tracker), }
+ catch (RuntimeException e) { deleteFromRawTable(...), }  // breaks the boot loop

It works. It stops the crash and breaks the boot loop. But “catch a wider exception” is a band-aid, not a fix. The root cause, an unchecked cast that allows a long to become a negative array size, remains.

The Bigger Picture: Mobile OS Privilege Separation

This vulnerability is a case study in a deeper problem: the privilege separation between Android’s telephony stack and the rest of the OS.

com.android.phone runs as a privileged system process. It’s responsible for the phone’s connection to the cellular network. When it crashes, the OS can’t gracefully recover because the crash takes down the core subsystem. There’s no watchdog, no isolated recovery. Just a restart that gets re-triggered by the unacknowledged message.

The deeper architectural question: why does a single, untrusted, remotely-receivable message get to crash a process that handles emergency calls? Why is there no sandbox that isolates the parsing of untrusted WAP Push data from the telephony signaling path?

This isn’t a theoretical concern. The interaction with Android’s 16KB page requirement and system-level memory management shows how kernel-level resource management decisions ripple through the entire stack. A negative array size that throws an uncaught exception in the telephony main thread is a resource management failure at the process level.

And the broader ecosystem isn’t any better. The hard-coded credentials in Android-based IoT devices we’ve covered before show that systemic OS security flaws extend far beyond smartphones into the devices that run Android under the hood.

Zero-Click Isn’t Just for Spyware Anymore

The SMS of Death is a denial-of-service attack, not spyware. But it exists in the same threat landscape as zero-click spyware delivered via targeted ads, a nightmare scenario that the Citizen Lab recently documented. Their AdFection report showed how mercenary spyware vendors like Candiru turned the entire online advertising ecosystem into a delivery pipeline, infecting devices at Al Jazeera with zero interaction from victims, just displaying a targeted ad was enough.

Photo Illustration of Spyware entering your space
Illustration of spyware potentially entering a device without user interaction.

The convergence is disturbing. We now have:

  1. Zero-click spyware delivered via ads, exploiting browser and OS vulnerabilities
  2. Zero-click DoS delivered via SMS, exploiting unchecked casts in telephony
  3. Zero-click exploitation via iMessage and WhatsApp (Pegasus, FORCEDENTRY)

And the line between “spyware” and “destructive” is blurring. The SMS of Death isn’t a surveillance tool, it’s a weapon. A remote attacker who knows a phone number can cut off the victim’s access to emergency services. In the right (wrong) circumstances, that’s lethal.

The Patch Gap Problem

The fix shipped in the October 2026 Android security update for Android 14 through 17. But here’s the uncomfortable truth: Android’s patch propagation is a mess.

Consider the timeline:

  • 5 May 2026: Vulnerability reported to Google via the Android VRP
  • 15 June 2026: Fix commit authored
  • October 2026: Fix ships in the regular security update
  • Ongoing: Devices on earlier patch levels remain vulnerable

Five months from report to public disclosure. That’s within Google’s 90-day disclosure policy window, so the timeline is defensible. But the fix landing in a monthly security update means it’s only as effective as the update ecosystem. And the Android update ecosystem is, to put it generously, uneven.

When the Qualcomm DSP kernel vulnerability CVE-2024-43047 was patched in October 2024, it took device manufacturers months to push updates. Millions of Snapdragon-chipset Android devices remained exposed. The same pattern plays out with every critical patch: Google fixes it, but the fix has to travel through Qualcomm, Samsung, Xiaomi, and a thousand other OEMs before it reaches an actual phone.

What This Means for Security Architecture

The SMS of Death is a small bug with big implications. It’s a reminder that:

1. Every untrusted input is a potential weapon. The WAP Push parser assumed the header length field would be a sane value. It’s a 25-year-old protocol assumption that never considered an attacker with a phone number.

2. Process isolation is only as good as its edge cases. com.android.phone is a system process that handles untrusted network data. It should be isolated, sandboxed, and have its crash handling carefully designed. It’s not.

3. Fixes that swallow exceptions don’t fix root causes. Catching RuntimeException prevents the crash, but it doesn’t validate input. The next unchecked cast in the same code path will be a different CVE.

4. The threat model changed. We used to think about malware. Then spyware. Now we need to think about weapons, attacks designed not to steal data but to cause physical harm by cutting off access to emergency services.

5. Regulation can make things worse. The Australian ECS determination is well-intentioned. But when the remedy for a compromised phone is to disconnect it from the network, the regulation becomes a weapon in the attacker’s hands.

The Bottom Line

The SMS of Death is a masterclass in how a single unchecked cast, in a process handling untrusted data, can become a remote, silent, persistent denial-of-service weapon. It’s a 5-byte message that can brick a phone, drop emergency calls, or get a victim’s device barred from carrier service.

The fix is out there. Update your devices. Check your patch level. And if you’re building software that handles untrusted input, take the lesson to heart: every (int) cast is a potential CVE.

The proof-of-concept is public on GitHub. The source is available under Apache License 2.0. The warning is clear: this is a working weapon, published for research and defensive testing only. It’s already been used in the wild, or at least, it can be.

Your phone is a brick away from being a brick. Stay patched.


The research and proof-of-concept were disclosed by security researcher Mark B, with recovery methodology contributed by @sakisDog. Full disclosure details are available at smsofdeath.com.

Share: