Exploiting PendingIntent Provenance Confusion to Spoof Android SDK Authentication
A single authentication bypass in a partner SDK grants attackers the identity of every partner in the ecosystem – and millions of apps use SDKs with exactly this vulnerability. OWASP’s 2024 Mobile Top 10 ranks Inadequate Supply Chain Security as the second most critical mobile risk, explicitly identifying third-party SDKs as a primary attack vector. Cross-app mobile SDKs – where a partner application communicates with a platform provider’s application via inter-process communication (IPC) – mediate sensitive operations such as content publishing, payment initiation, and identity federation. Unlike embedded libraries that execute within a single app’s process, cross-app SDKs require the provider’s service to authenticate the calling application at runtime. A pattern sometimes used for this authentication relies on PendingIntent.getCreatorPackage() to verify sender identity. We demonstrate that this mechanism exhibits a fundamental provenance confusion vulnerability: a PendingIntent reliably identifies who created it but cannot attest who presents it – and this distinction is fatal for authentication. An attacker app with notification access can steal a legitimate partner’s PendingIntent via NotificationListenerService and replay it to impersonate that partner, bypassing authentication entirely. The attack succeeds against both mutable and immutable PendingIntents because immutability protects the token’s contents, not its provenance. We systematically evaluate eight Android IPC authentication mechanisms against an SDK-specific threat model and present a defense architecture combining Bound Service IPC with kernel-level caller verification via Binder.getCallingUid(), supplemented by server-side certificate-hash validation. This provides authentication guarantees while remaining scalable across partner ecosystems.
💡 Research Summary
The paper investigates a systemic authentication flaw in many cross‑application Android SDKs that rely on PendingIntent.getCreatorPackage() to verify the identity of the calling partner app. In this model, the SDK library embedded in a partner app creates a PendingIntent that encodes the partner’s package name; the SDK provider’s service extracts the creator package from the token and checks it against a server‑maintained allow‑list. The authors demonstrate that this approach suffers from a fundamental “provenance confusion” vulnerability: a PendingIntent unambiguously records who created it, but it provides no guarantee about who presents it. Consequently, any process that obtains a reference to a legitimate partner’s PendingIntent can replay it and be authenticated as that partner.
The attack vector exploits the NotificationListenerService (NLS) permission, which many legitimate apps request to monitor notifications. An attacker‑controlled app registers an NLS, intercepts every StatusBarNotification posted by the target partner, extracts the embedded PendingIntent (e.g., contentIntent, actionIntent, deleteIntent), and stores it. When the attacker later invokes the SDK’s API, it supplies the stolen PendingIntent instead of a locally created one. The provider’s service calls getCreatorPackage(), receives the original partner’s package name, finds it on the allow‑list, and authorizes the request. The attack works against both mutable and immutable PendingIntents because immutability only protects the Intent’s payload, not the token’s provenance.
The authors systematically evaluate eight common Android IPC and application‑layer authentication mechanisms—startActivityForResult, getReferrer(), PendingIntent.getCreatorPackage(), BroadcastReceiver permissions, ContentProvider permissions, signature/knownSigners permissions, PKCE, and Bound Services—against a threat model specific to SDK partner authentication. Most of these mechanisms either share the same provenance confusion flaw or lack kernel‑level caller verification, making them vulnerable in similar scenarios.
To mitigate the issue, the paper proposes a three‑layer defense architecture. The first layer uses a bound service to restrict IPC to a well‑defined interface, preventing arbitrary token delivery. The second layer leverages the Binder driver’s Binder.getCallingUid() to obtain the Linux UID of the actual caller at the kernel level and validates it inside the service. The third layer adds server‑side verification: the provider’s backend stores a hash of each partner’s signing certificate and the expected UID; when a request arrives, the server checks that the creator package reported by the PendingIntent matches the stored certificate hash and UID. This combination ensures that even if a malicious app steals a PendingIntent, it cannot satisfy both the UID and certificate‑hash checks, thereby blocking the authentication bypass.
A proof‑of‑concept implementation on Android 14 validates the attack (100 % success) and the defense (100 % block rate). The defense requires no changes to existing SDK clients; only the provider’s service and backend need to be updated, making it scalable for large partner ecosystems.
In conclusion, the paper reveals that PendingIntent‑based authentication, widely adopted in production SDKs (e.g., WhatsApp one‑tap auto‑fill, Chromium’s IntentHandler, Termux plugin architecture), is intrinsically insecure due to provenance confusion. The authors call for a shift away from creator‑package checks toward kernel‑enforced UID verification combined with server‑side certificate validation, and they recommend that Android platform policies explicitly forbid using PendingIntent.getCreatorPackage() as an authentication primitive. This work highlights a new class of SDK‑level attacks that can compromise partner identities, enable unauthorized content publishing, payment initiation, and identity federation at ecosystem scale.
Comments & Academic Discussion
Loading comments...
Leave a Comment