...[ More ]
Android's CALL_PHONE permission, shown to users as "make and manage phone
calls", also authorises execution of carrier MMI/USSD codes against the SIM.
The permission text does not mention this, no confirmation is shown before
execution -- a transient "USSD code running" dialog appears only afterwards
--
and MMI execution writes no call log entry. Where a CALL_PHONE-holding app
also
exposes a browser-reachable deeplink into an auto-dial path, the capability
becomes remotely triggerable with a single tap.
Demonstrated against ACR Phone / Cube ACR (com.nll.cb, 5M+ installs), which
declares an intent filter carrying action CALL_BUTTON, category BROWSABLE
and a
tel: scheme, resolving to an activity that dials rather than pre-fills.
Chrome's
intent: URI syntax lets a page nominate an arbitrary action, and Chrome's
only
check is that the resolved filter declares BROWSABLE, so the string executes
under ACR's own CALL_PHONE grant rather than any grant held by the browser.
No
chooser appears (ACR is the sole handler) and no confirmation is requested.
The
terminating hash must be percent-encoded as %23 -- a literal # parses, but
is
lost further down the dial path, and the remainder is placed as an ordinary
call.
intent:*21*5550000000%23#Intent;scheme=tel;action=android.intent.action.CALL_BUTTON;end
One tap registers unconditional call forwarding to the attacker's number.
Incoming calls -- including voice-delivered OTPs and bank verification
callbacks
-- are then delivered to the attacker. Registration is held in the carrier
network rather than on the handset, so it survives reboot, uninstalling the
app
and a factory reset, and persists until cancelled. Clear with ##21#,
interrogate
with *#21#. Both *21*<n>%23 and **21*<n>%23 register.
Preconditions for the demonstration: ACR must hold CALL_PHONE and the DIALER
role. Both are the ordinary state for a dialer replacement, but neither is
automatic. The role matters twice over -- ACR's own DialerActivity.a0()
redirects to setup without it, and Android 14 added a platform check that
refuses dangerous MMI codes from a non-default dialer, which ACR being the
default dialer satisfies. Of 88 call, dialer and VoIP apps scanned at the
manifest level, 66 declared CALL_PHONE and 54 exposed some browser-reachable
dial surface; most pre-fill rather than dial, so whether any given one is
exploitable turns on its own deeplink handling, while the platform grants
the
underlying capability to all of them uniformly.
A related Android 17 change removes the need for a vulnerable third-party
app
altogether. Telecom moved into the com.android.telephonycore mainline
module and
its UI into a separate privileged application; com.android.server.telecom
is now
a shim whose UserCallActivity re-starts the intent against
com.google.android.telecomui, which calls TelecomManager.placeCall() as
itself.
The launching package is not carried across. placeCall() binds the caller
to the
binder UID, and telecomui holds CALL_PRIVILEGED, so the dangerous-MMI check
--
which still runs on every call -- is evaluated against telecomui and
passes. A
plain **21*<number># sent via ACTION_CALL by an app holding only CALL_PHONE,
with no dialer role, is therefore dispatched as an MMI code. Reported
separately; confirmed on an emulator only.
Tested on: Samsung Galaxy M16 5G, Android 16 (One UI 8.5), build
BP4A.251205.006.M166PXXS7DZG1, security patch level 5 July 2026, against a
live
Airtel India network (single-asterisk form). Reproduced on Android 14 (API
34)
and Android 17 (API 37, patch 2026-07-05) emulators, double-asterisk form
against the simulated network.
Vendor status: Google closed the platform report as Won't Fix (Infeasible),
assessing it as insecure deeplink handling in third-party dialers rather
than an
Android vulnerability. The Android 17 trampoline report was closed as a
duplicate of an earlier internal report. The ACR Phone developer responded
within 48 minutes and committed a fix to the next release; the Play release
is
pending Google's review.
Timeline:
12 Sep 2026 - Reported to the Android & Google Devices VRP
14 Sep 2026 - Android 17 retest added; TelecomUi trampoline reported
separately
17 Sep 2026 - Platform report closed Won't Fix (Infeasible)
24 Sep 2026 - Trampoline report closed as duplicate of an internal Google
report
25 Sep 2026 - Request to be added to that report declined
09 Oct 2026 - Reported to the ACR Phone developer; acknowledged, fix
committed
09 Oct 2026 - Public disclosure
Full write-up:
https://karansaini.com/mmi-android/
Sincerely,
Karan SainiData
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
15 Oct 2026 00:00Current
6.2Medium risk
Vulners AI Score6.2