Share
## https://sploitus.com/exploit?id=A98E34DB-8E36-542C-B516-BA03753D3AFE
# CVE-2026-12960

**Improper Export of Android Application Components in the ASUS Router App**

A component bundled in the ASUS Router Android app (`com.asus.aihome`) was declared
`android:exported="true"` with no `android:permission`. Any other app on the same
device, holding zero permissions, could send it a crafted `Intent` and make the ASUS
Router app open an attacker-controlled URI on the user's behalf.

Reported to ASUS on 2026-03-17. Fixed by ASUS and published as
[CVE-2026-12960](https://vulners.com/cve/CVE-2026-12960) on 2026-07-03.

Discovered and reported by [Sedric Louissaint](https://sedriclouissaint.com) of
[Show Up Show Out Security](https://susos.co).

---

## Summary

| | |
|---|---|
| **CVE** | [CVE-2026-12960](https://nvd.nist.gov/vuln/detail/CVE-2026-12960) |
| **Product** | ASUS Router App for Android (`com.asus.aihome`) |
| **Affected** | โ‰ค 1.0.0.9.71 |
| **Fixed in** | 1.0.0.9.74 |
| **Weakness** | [CWE-926: Improper Export of Android Application Components](https://cwe.mitre.org/data/definitions/926.html) |
| **CVSS 4.0** | 6.0 Medium `CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:N/SA:N` |
| **CNA** | ASUS |
| **Vendor advisory** | https://www.asus.com/security-advisory/ |
| **Tested on** | `com.asus.aihome` 1.0.0.9.71 (Google Play), Android 11 emulator |

## Technical detail

The app bundles the Baidu Push SDK, which declares:

```xml

```

No `android:permission` attribute, so Android's component-level access control never
runs. Any installed app can call `startService()` against it.

`CommandService.onStartCommand()` reads a `PublicMsg` Parcelable out of the incoming
Intent's `public_msg` extra and passes it to `handlePrivateNotification()`, which
branches on the attacker-supplied `mOpenType` field:

| `mOpenType` | Behaviour |
|---|---|
| `1` | `startActivity(ACTION_VIEW, Uri.parse(mUrl))` with the attacker's `mUrl` |
| `2` | `Intent.parseUri(mPkgContent, 0)` then `startActivity()` / `sendBroadcast()` |

Neither the sender nor the payload is validated. Because the resulting activity is
launched from the ASUS app's own UID and process, whatever appears on screen appears
to have come from the trusted router-management app the user just opened.

Nothing about this is Baidu-specific in effect. The SDK ships the exported component,
the host app inherits it, and the host app's identity is what gets borrowed.

### Attack chain

1. Malicious app constructs a `PublicMsg` Parcelable matching the target's field layout.
2. Sets `mOpenType = 1` and `mUrl` to an attacker-controlled URI.
3. Sends the Intent to `CommandService`. No permission required, no `SecurityException`.
4. `onStartCommand()` โ†’ `handlePrivateNotification()`.
5. `startActivity(ACTION_VIEW, Uri.parse(mUrl))` fires from the ASUS app's process.

The `PublicMsg` field order, recovered from `writeToParcel` in the decompiled smali and
reimplemented in [`poc/PublicMsg.java`](poc/PublicMsg.java):

```
String mMsgId, mAppId, mTitle, mDescription, mUrl, mPkgName
int    mPkgVercode, mNotificationBuilder, mNotificationBasicStyle
int    mOpenType, mUserConfirm
String mCustomContent, mPkgContent
int    mAdvertiseStyle
String mAdvertiseSmallIconUrl, mAdvertiseLargeIconUrl, mAdvertiseClickUrl,
       mAdvertiseBigPictureUrl, mAdvertiseBigPictureClickUrl, mAdvertiseDownloadClickUrl
```

Get the order wrong and the Parcel unmarshals into garbage. Get it right and the
service accepts the message as if Baidu's own push infrastructure sent it.

### Demonstrated payloads

Six URI schemes, one exported service, zero permissions:

| # | Scheme | Result |
|---|---|---|
| 1 | `https:` | Browser opens an attacker-controlled phishing page |
| 2 | `sms:` | SMS composer pre-filled with a social-engineering message |
| 3 | `tel:` | Dialer pre-filled with an attacker-controlled number |
| 4 | `mailto:` | Email composer pre-filled to exfiltrate credentials |
| 5 | `market:` | Play Store redirect for a malware install |
| 6 | `geo:` | Maps redirect to a fake service centre |

## Proof of concept

[`media/poc_commandservice.mp4`](media/poc_commandservice.mp4) is the full 31-second
run: build, install, fire, and the emulator reacting to each payload in turn.

| Attack 1: phishing page | Attack 2: SMS composer | Attack 3: dialer | The PoC app's permissions |
|---|---|---|---|
| ![Browser opened to an attacker URL](media/attack1-browser.jpg) | ![SMS composer pre-filled with a fake ASUS security alert](media/attack2-sms.jpg) | ![Dialer pre-filled with an attacker number](media/attack3-dialer.jpg) | ![Android App info screen showing "No permissions requested"](media/poc-app-no-permissions.jpg) |

That last screenshot is the whole argument. **No permissions requested.** The app that
just drove six actions through the ASUS Router app asked the user for nothing at all.

### Reproducing

Requires ADB, a JDK, and the Android SDK build tools (`aapt2`, `d8`/`dx`, `zipalign`,
`apksigner`) plus `platforms;android-30`.

```bash
./poc/poc_commandservice_exploit.sh 
```

The script runs three phases:

1. **Access check.** Sends the three `CommandService` actions from `com.android.shell`
   and reports whether any are rejected. A permission-protected service throws
   `SecurityException` here. This one accepted all three.
2. **Build.** Compiles the PoC, packages and signs `exploit_commandservice.apk`, and
   installs it. A prebuilt copy is in [`poc/`](poc/) if you would rather skip this.
3. **Execute.** Brings the ASUS app to the foreground, launches the PoC from an
   unprivileged app context, and captures the logcat evidence.

Phase 1 output on a vulnerable device:

```
[ACCESS]  passthrough.notification.CLICK โ†’ service accepted intent
[ACCESS]  privatenotification.CLICK      โ†’ service accepted intent
[ACCESS]  privatenotification.DELETE     โ†’ service accepted intent

  Phase 1 result: 3/3 actions accepted without permission check
```

And the `ServiceRecord` from `dumpsys activity services`, which records the caller:

```
intent={act=com.baidu.android.pushservice.action.privatenotification.CLICK
        cmp=com.asus.aihome/com.baidu.android.pushservice.CommandService}
recentCallingPackage=com.android.shell
startRequested=true callStart=true
```

Phase 3, from a real unprivileged app rather than the shell:

```
W PoCExploit: [OK] attack1_url_open โ†’ com.asus.aihome/com.baidu.android.pushservice.CommandService
W PoCExploit: [OK] attack2_sms_compose โ†’ ...
(all 6 succeed)
```

`startService()` returned the target `ComponentName` instead of `null`, and no
`SecurityException` was thrown. Android resolved the Intent and delivered it.

## Repository contents

```
poc/
  poc_commandservice_exploit.sh   Automated three-phase reproduction script
  ExploitCommandService.java      PoC activity + broadcast receiver source
  PublicMsg.java                  Parcelable matching the target's field layout
  AndroidManifest_PoC.xml         PoC manifest (note: no )
  exploit_commandservice.apk      Prebuilt PoC, debug-signed, zero permissions
media/
  poc_commandservice.mp4          Full PoC recording
  attack1-browser.jpg             Stills pulled from the recording
  attack2-sms.jpg
  attack3-dialer.jpg
  poc-app-no-permissions.jpg
vendor/
  asus-security-advisory-submission.pdf   The report as filed with ASUS
```

The PoC's outbound URL is a Burp Collaborator subdomain that was used to confirm the
navigation actually happened. It is long dead. Swap in your own if you are reproducing.

## Remediation

For the vendor, the fix is one attribute:

```xml

```

Or, if the component genuinely has to be reachable from outside, gate it with a
`signature`-protection-level permission and validate the deserialised `PublicMsg`
before acting on it. ASUS shipped the fix in 1.0.0.9.74.

For users: update the ASUS Router app to **1.0.0.9.74 or later**.

For everyone else shipping Android apps: audit what your third-party SDKs export.
Run `aapt dump xmltree base.apk AndroidManifest.xml` against your own release build
and read every `exported="true"` in it. The manifest you ship is the sum of every
manifest you merged, and you own all of it.

## Timeline

| Date | Event |
|---|---|
| 2026-03-17 | Reported to ASUS with PoC APK, automated script, and video |
| 2026-06-23 | CVE-2026-12960 reserved by ASUS as CNA |
| 2026-07-03 | CVE published; fix available in 1.0.0.9.74 |
| 2026-07-25 | Public write-up and PoC released |

## Write-ups

- Personal account: https://sedriclouissaint.com/blog/asus-router-app-exported-commandservice-cve-2026-12960
- Show Up Show Out Security: https://susos.co/blog/improper-export-of-android-components-in-the-asus-router-app-cve-2026-12960

## Disclaimer

Published after coordinated disclosure and a vendor fix, for defensive and educational
use. The PoC targets a patched version and does nothing but launch URIs. Do not run it
against devices you do not own or have written authorisation to test.