Malformed WAP Push SMS Crashes Calls, Including Emergency Calls, on Android

- Reading
- 7 min
- Code
- 5
A malformed WAP Push message kills Android's telephony process without any interaction from the victim, dropping active calls and leaving the device stuck in a reboot loop.
The Bug That Doesn't Even Need a Tap
A single malformed SMS of the WAP Push type can crash Android's telephony process without the victim seeing anything on screen. The flaw was reported by a researcher identified as Mark B. on May 5, 2026, through Google's Android & Devices VRP bug bounty program, and became public on October 29, 2026, along with a proof-of-concept app and the full source code published on GitHub under the Apache 2.0 license.
The vector is a WAP Push message delivered over port 2948, handled as a data SMS: it never appears in the message inbox and the sender's number is never shown to the victim. There's no tap, no app to open, no notification: the exploitation is entirely silent and remote, requiring nothing more than knowing the target's phone number.
A Casting Bug, Not a Business-Logic One
The bug lives in WapPushOverSms.decodeWapPdu(), part of Android's telephony framework (frameworks/opt/telephony), code that runs on practically every manufacturer that ships the system. When processing the WSP header of a WAP Push message, the function reads the header length as a uintvar, a value that arrives as a long, and casts it to int with no range check before using it as the size of a new byte array.
// WapPushOverSms.java:217 - header length read as a long, with no bounds checking
int headerLength = (int) pduDecoder.getValue32();
...
// WapPushOverSms.java:244 - the cast value becomes the array size
byte[] header = new byte[headerLength];A 5-byte uintvar such as 88 80 80 80 00 decodes to 0x80000000. Converted to a signed 32-bit int, that value becomes -2147483648. Allocating new byte[-2147483648] throws an unhandled NegativeArraySizeException on the telephony main thread, which kills the com.android.phone process:
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)The affected code has been present since Android 12, with reproduction confirmed through Android 16. Google's October 2026 security update fixes the issue only for Android 14 through 17: devices stuck on Android 12 or 13, outside the security support window, keep running the same vulnerable code, with no fix planned.
The Damage in Practice
The report documents a set of effects that go far beyond an isolated crash:
- Zero-click and silent: nothing appears in Messages, no notification, no indication for the victim.
- Drops active calls, including emergency calls, with
DisconnectCause CS_DEATHthe moment the process restarts. - Telephony blackout: 1 to 2 seconds without service each time a message is processed, while
com.android.phonecomes back up. - Carrier resend amplifies the attack: an unacknowledged message gets resent by the network, crashing the device again; in testing, a single message caused intermittent outages for up to a week.
- About 20 messages render the device unusable for an extended period.
- The malicious message stays queued in
content://sms/rawand is reprocessed on every boot, trapping the phone in a reboot loop until it's manually removed.
Testing covered multiple manufacturers and models, including a Pixel 9 on April 2026 firmware and devices in the Galaxy and Galaxy A lines, with a 100% reproduction rate.
Recovering the Device Without Wiping Everything
Once the reboot loop starts, Android's RescueParty mechanism reboots the device into recovery mode roughly every 90 seconds, as if something in the system were corrupted. At that point, the average user only sees a prompt to wipe factory data, exactly the scenario Google's Vulnerability Rewards Program classifies as a "Destructive Remote DoS."
User @sakisdog documented, in issue 2 of the repository, a less destructive recovery method: deleting only the malicious message's rows via ADB, in the short window after boot completes, instead of accepting the factory wipe.
adb shell content query --uri content://sms/raw --projection _id:destination_port:date:deleted
adb shell cmd appops set com.android.shell WRITE_SMS allow
adb shell content delete --uri content://sms/raw --where "address='<SENDER>'"
adb shell cmd appops set com.android.shell WRITE_SMS defaultAs a last resort, adb shell pm clear com.android.providers.telephony resolves the loop, but wipes the entire SMS/MMS history and the device's APN settings. Even the less destructive path requires a computer, ADB enabled, and timing during the boot window, something out of reach for a non-technical user caught in the loop, who typically ends up choosing the factory reset.
Why This Goes Beyond an Ordinary Crash
In Australia, access to emergency calls is treated as a mandatory property of a mobile service, not an optional feature. Under the Telecommunications (Emergency Call Service) Determination, administered by the ACMA (Australia's communications regulator), carriers are required to identify devices that can't dial 000, help the customer migrate to a working device and, if nothing is done, block the affected device's service. Telstra, an Australian carrier, states publicly that it's required to block, within 28 days, phones that have lost the ability to call 000.
The side effect is perverse: the regulatory remedy for a phone that can't call emergency services is to pull it off the network, not fix the operating system. A remote attacker who induces this condition can, in practice, get the carrier itself to block the victim's device until it's updated. The rule was reinforced in 2024, after the 3G network shutdown left some devices able to make regular calls but unable to reach emergency services, the same functional state this flaw triggers on demand.
The material consulted for this report is centered on Australian regulation; the sources give no indication of how regulators such as Anatel, Brazil's telecoms regulator, would handle an equivalent scenario of remote loss of access to emergency services in Brazil, which remains an open question for anyone who follows telecom regulatory policy in Brazil.
What Google Fixed (and What It Didn't)
On the same day as the initial report, May 5, 2026, the researcher had already proposed the obvious fix: validate the size before the cast.
long rawHeaderLen = pduDecoder.getValue32();
if (rawHeaderLen < 0 || rawHeaderLen > pdu.length) {
result.statusCode = Intents.RESULT_SMS_GENERIC_ERROR;
return result;
}
int headerLength = (int) rawHeaderLen;That's not what Google shipped. Commit 735d967, "Fix remote DoS in decodeWapPdu," was authored by an Android engineer on June 15, 2026, and landed in the October 2026 security bundle for Android 14 through 17. Instead of validating the length, it widens the catch block to cover RuntimeException and starts deleting the offending message from the queue as soon as the exception is caught:
- } catch (ArrayIndexOutOfBoundsException aie) {
+ } catch (RuntimeException e) {
+ try { success = processMessagePart(tracker); }
+ catch (RuntimeException e) { deleteFromRawTable(...); } // stops the boot loopThe negative-size allocation still happens; what changed is that the exception no longer propagates and the poison message stops being reprocessed on every boot or carrier resend, which eliminates the reboot loop. It's a fix for the symptom, not the root cause: the bounds check originally proposed was never adopted.
What Changes for Those Who Build Software
The failure pattern here isn't exclusive to telephony: any parser that reads a length from an untrusted source, casts it to int, and uses the result directly as an allocation size is subject to the same bug. That includes parsers for proprietary binary formats, QR code payloads, Bluetooth or NFC messages, and even hand-rolled protobuf deserialization without bounds validation.
The practical lesson for anyone writing this kind of code is simple: the bounds check has to come before the cast, comparing the value as a long against the actual size of the available buffer, never after it's already been truncated to int. Broadly catching RuntimeException, as Google did, is a safety net against crashes, not a defense against the invalid allocation logic itself.
For teams assessing production risk, the picture is concrete: devices on Android 12 and 13 remain exposed indefinitely, outside the security update window, and the proof of concept is already public and functional on GitHub. That moves the flaw from the "theoretical risk" category to something that should enter any threat model involving SMS receipt, including apps that auto-read OTPs or any integration that depends on the state of the device's telephony process.
What Still Remains Open
Two gaps remain unanswered in the available sources: there's no announced timeline for Android 12 and 13 to receive any mitigation, and it's unclear whether carriers can filter malformed WAP Push messages at the network edge before they reach the device. Until that changes, the practical defense remains keeping the October 2026 patch or later installed, the only layer that currently stops the reboot loop.
Translated from the Brazilian Portuguese original · Read the original
Mistral Large 4 (Le Chonk) becomes a 1-trillion-parameter open model
Mistral AI released the weights of Large 4, codenamed Le Chonk, a multimodal model with 1 trillion parameters that leads open code benchmarks, with a high refusal rate for malicious security requests. For those looking to escape closed APIs, the announcement comes with important caveats about infrastructure and licensing.





