Arbitrary App Installation on Intune Managed Android Enterprise BYOD

From Work Profile to Fun Profile

Published August 28, 2025 · 20 min read

TLDR; It's possible to install arbitrary apps in a provisioned Work Profile on a BYOD device with ADB and Android Studio after the patch of CVE-2023-21257. Due to a auto-install requirement in the Work Profile, which can be enforced via Intune, it is possible to convince the Play Store service (Finsky) to install an arbitrary app, with the same package name and a higher version number than the managed legit application. If a per-app VPN connection is configured via MS Tunnels and Defender application for the managed application, it is even possible to take over the VPN connection and have access to the internal systems.

Background

In June 2023, i had the chance to do some testing and research with Microsoft Intune and Android Enterprise in a (bring-your-own-device) BYOD scenario. Microsoft Intune is a cloud-based service that provides unified endpoint management, allowing organizations to manage and secure devices, applications, and data across various platforms, including Windows, macOS, iOS, and Android. Android Enterprise is a set of APIs and tools from Google that enables organizations to manage and secure Android devices for business use, allowing for the separation of work and personal data on a single device and providing granular control over apps and settings. The basic idea is to give the employees the opportunity to have business related apps with internal data on their phones, but in a secure way.

During the analysis, we tested several vectors like if sharing data between private and work apps is enabled / possible, are screenshots enabled and stuff like that. We also noticed that some apps were required and auto downloaded due to company policies. Of course, this is all extremely dependant on the configuration of the respective policies pushed to the devices. Some not-so-interesting-compliance-checks-days later, we thought maybe it is possible to install arbitrary apps via ADB CLI. Since it is was private device (BYOD), the employee can activate the Developer Options options very easy.

As we already knew, Android has multi user support and this is especially relevant for Work Profiles. Whenever a Work Profile is created on a device, an additional user is created with his own filesystem and relevant apps. This usually looks like this on a regular phone: main user is user 0 and the Android Enterprise Work Profile user could be user 1 (depending how many Work Profiles / other profiles were already created). This brings the advantage that the filesystem, system apps and everything relevant is absolutely isolated from one another. For useability and convenience reasons the Work Profile is then merged into the regular UI, as shown below:

Android Enterprise Work Profile

So we turned on the Developer settings and ADB on the phone tried to install an APK from our notebook via ADB CLI adb install test.apk and unfortunately it didnt work and was not installed. As we knew, the Work Profile has their own userid so we tried to install it via adb install --user 1 test.apk but this also did not work and we got a permission error.


jgr@desktop % adb shell
emu64a:/ $ pm list users
Users:
	UserInfo{0:Owner:4c13} running
	UserInfo{1:Work profile:1030} running
emu64a:/ $ %


jgr@desktop % adb install --user 1 Zebra\ Utilities_2.0.5152_APKPure.apk
Performing Streamed Install
adb: failed to install Zebra Utilities_2.0.5152_APKPure.apk:
Exception occurred while executing 'install':
java.lang.SecurityException: Shell does not have permission to access user 1
 com.android.server.am.ActivityManagerService.handleIncomingUser:13871 android.app.ActivityManager.handleIncomingUser:5300 com.android.server.pm.PackageManagerShellCommand.translateUserId:3965
	at com.android.server.am.UserController.handleIncomingUser(UserController.java:2895)
	at com.android.server.am.ActivityManagerService.handleIncomingUser(ActivityManagerService.java:13871)
	at android.app.ActivityManager.handleIncomingUser(ActivityManager.java:5300)
	at com.android.server.pm.PackageManagerShellCommand.translateUserId(PackageManagerShellCommand.java:3965)
	at com.android.server.pm.PackageManagerShellCommand.doCreateSession(PackageManagerShellCommand.java:3976)
	at com.android.server.pm.PackageManagerShellCommand.doRunInstall(PackageManagerShellCommand.java:1626)
	at com.android.server.pm.PackageManagerShellCommand.runInstall(PackageManagerShellCommand.java:1562)
	at com.android.s%
			

I can't really remember why (i think i got the hint from a stackoverflow article :D) but i then tried it to install a pretty basic self developed app with the package name com.testapp.main via Android Studio, with the configuration setting install for all users.

Install for all users in Android Studio

Suprisingly, this worked. We had now an arbitrary app installed with our own package name in the private and the Work Profile. We added this finding to the report and wrapped it up.

Further investigation

A couple of weeks later, in late August 2023, i wanted to come back to this problem, because i found it pretty weird that it wasn't possible to install arbitrary apps via ADB CLI, but it worked with Android Studio. So, i thought, maybe Android Studio sends some different ADB commands over USB or something. So, i set up an Intune trial tenant, created some policies according to the ones we saw in the engagement and created test users to login via the Company portal app on my test phone. I didn’t even get to the USB debugging part, because it did not work anymore.

So, i debugged other things for several hours, tried several different apps and versions and could not figure out what was different than a couple of weeks ago. By suprise, i had a look at the Android Security Bulletin from July 2023 and saw a disclosed vulnerability which looked very suspiciously like a patch for our little party trick from June and my phone for testing was of course in auto-update mode.

CVE References Type Severity Updated AOSP versions
CVE-2023-21257 A-257443065 EoP High 13

The patch had the following description:


[RESTRICT AUTOMERGE] Prevent installing apps in policy restricted work profile using ADB

If DISALLOW_DEBUGGING_FEATURES or DISALLOW_INSTALL_APPS restrictions are
set on a work profile, prevent side loading of APKs using ADB in the work profile.

Bug: 257443065
Test: atest CtsPackageInstallTestCases:UserRestrictionInstallTest
			

So, what has been changed?


@@ -2093,9 +2093,25 @@
        // The caller explicitly specified INSTALL_ALL_USERS flag.
        // Thus, updating the settings to install the app for all users.
                for (int currentUserId : allUsers) {
-                    ps.setInstalled(true, currentUserId);
-                    ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId,
+                    // If the app is already installed for the currentUser,
+                    // keep it as installed as we might be updating the app at this place.
+                    // If not currently installed, check if the currentUser is restricted by
+                    // DISALLOW_INSTALL_APPS or DISALLOW_DEBUGGING_FEATURES device policy.
+                    // Install / update the app if the user isn't restricted. Skip otherwise.
+                    final boolean installedForCurrentUser = ArrayUtils.contains(
+                           installedForUsers, currentUserId);
+                    final boolean restrictedByPolicy =
+                           mPm.isUserRestricted(currentUserId,
+                                    UserManager.DISALLOW_INSTALL_APPS)
+                            || mPm.isUserRestricted(currentUserId,
+                                   UserManager.DISALLOW_DEBUGGING_FEATURES);
+                    if (installedForCurrentUser || !restrictedByPolicy) {
+                        ps.setInstalled(true, currentUserId);
+                        ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId,
                            installerPackageName);
+                   } else {
+                      ps.setInstalled(false, currentUserId);
+                    }
                }
           }
			

When i had closer look at the code, i wondered if it would be possible to install (update) an arbitrary app with the same package name as an already installed one. So i recreated the environment i had seen in June 2023, configured the Intune policies and added the Workday application to the required applications (automatic downloading and installing) of the group from my test user, because the seen environment from June 2023 also had this setting enabled.

Workday app as required for Android BYOD group

Some hours later and trying different things, i thought that it maybe should be possible to try and convince Android that my arbitrary app with the same package name as an already installed app, could be an update when the version number is higher than the actual one. 💡

So i adjusted the Gradle [Module:app] file of my sample app, with the assumption that the actual version name and version code of the application is 1.0 for example and the applicationId, namespace, packagename is known e.g. com.workday.workdroidapp:


	[...]
	android {
	    namespace = "com.workday.workdroidapp"
	    compileSdk = 36

	    defaultConfig {
	        applicationId = "com.workday.workdroidapp"
	        minSdk = 31
	        targetSdk = 36
	        versionCode = 900000004
	        versionName = "9000000004.0"

	        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
	    }
	[...]
			

When i checked that the setting to install for all users is still active and pressed the Debug button in Android Studio with the attached phone, i was immediatly greeted with the following notification:

Debug install notification

So i clicked OK and immediatly saw the installation of my arbitrary app in the personal profile and the real Workday app, which we took the package name from for our arbitrary app, was deinstalled. I was a bit confused, because i actually thought after the error message it is not possible to update the legit app with my abitrary one and Android would just skip the installation to the Work Profile.

I re-checked the company settings via Company Portal application on the phone and to my suprise, 1 minute later i saw a little notification from the Work Profile Play Store app (as i mentioned earlier, the work profile has their own set of system applications which are solely used for Work Profile stuff) that my application Workday has been successfully installed.

PlayStore notification of arbitrary app

At that point, i was totally confused. I repeated the steps several times, from uninstalling the work profile as a whole, reinstalling and onboarding via Company portal and then try to update the Workday app with my arbitrary one and it worked very reliable in 1-10min to replace the legit app with my arbitrary one, depending on the speed of which the policies and the missing required app (Workday) is checked and noticed on the device. I reread the patch from Android several times, and also checked the permission of the UserManager in the Work Profile, despite i just did a default configuration via Intune.

So, I retested all of this in August 2025 with Android 16 (API Level 36) (Security Patch April 2025), as well as Android 13 (API Level 33) (Security Patch March 2024) and it still works.

Proof of Concepts:

PoC with Android 13 (submitted to Android VRP with Security Patch August 2023):

PoC with Android 16 (tested in August 2025 with Security Patch April 2025):

So my idea why this whole chain worked was: When my arbitrary application is pushed to the device and to both users (private and work profile user) it gets installed for the private one, because there are no restrictions. For the Work Profile user, the APK gets pushed to the device into a temporary directory, then the check from the patch applies but fails because according to the usermanager object at least one of the flags DISALLOW_DEBUGGING_FEATURES or DISALLOW_INSTALL_APPS is set for the Work Profile user and in parallel the legit app is deinstalled because it thinks it could be an update. At this point the legit app is deinstalled from the Work Profile. When then a recheck of the applied Intune policies via Company Portal is triggered, it also checks if all required apps are installed. When not, the Work Profile Play Store service (internal name Finsky) checks with Play Services online and also this temporary directory, compares the latest online version with the version in the temporary directory and if the temporary directory version is higher, then our arbitrary apps is installed. And most probably the Play Service does not check if the flags DISALLOW_DEBUGGING_FEATURES or DISALLOW_INSTALL_APPS are set.

So when i thought i had an idea why this happens and how it works, i was confident this could be a bypass for CVE-2023-21257. So i opened an issue on the Google and Alphabet Vulnerability Reward Program (VRP) platform, documented everything and sent the bug report at end of August 2023.

After a couple of weeks i got a response from Android VRP and with the answer that they consider this not as a vulnerability, the MDM needs to restrict this.

Answer Android VRP

In my opinion, the MDM does actually restrict this with the set flags (see pictures, left the private profile and right Work Profil) and the check also works, but there is most probably some sort of caching problem with the PlayStore service.

Private profile with no restrictions Work Profile with set restrictions

Further Further Investigation - What could i do with my own app in a Work Profile?

Besides the obvious, that usually sharing data between private and Work Profile is disabled, you have here a nice way to exfil data because you have now an application in the work context which you can share data to. Furthermore, there is also a setup i've seen in Intune with MS Tunnels, in which you can configure a per-app VPN. This means that a configured app on the device can connect via VPN to your network e.g. for an accounting application or internal employee directory. If you replace an application in the Work Profile with a configured per-app VPN setting with the party trick from above, it is also possible to use the VPN connection to the connected network with the arbitrary application.

Final Thoughts

So of course, the prerequirements are very high, but if you're able to access someones BYOD device unlocked (Developer Settings need to be activated, otherwise you would need to know the device PIN/password to activate) you would be able to replace a legit business application with a malicous one for long-term access to company data. Additionally, if activated and if you are able to replace the correct one, you would also be able to pivot into the internal network via the per-app-VPN.

Mitigations

To my current knowledge, the only setting that effectively mitigates this at the moment is disabling the automatic download and installation of apps (not configuring as required) in the Work Profile, but instead using available for enrolled devices setting. Other policies, such as disabling Developer Settings for all profiles or blocking installations from unknown sources, can be easily bypassed with proper timing. It it also questionable if employees would accept such a restriction on their private phone and in their private profile. Nonetheless the company tries to save money with not providing a dedicated work device and piggybacks the private ones.

Let me know if you have additional ideas, then please ping me or let me know on X (https://x.com/joelgun)

References