When developing for mobile, applications often have to request some permissions from the system. They might need access to the user's contacts, to the Bluetooth connection or the ability to send SMS messages. All of the permissions mentioned above are platform permissions, defined by the Android framework.

But there are cases for when these don't suffice and the application needs to define their own custom permission. I'll use our own company as an example. Secure Code Warrior might create an app that saves some private data as part of a profile, including the user's performance on the SCW platform. And we would like to allow another security training app, say DevTrainer, to use this data if the user gives them permission to do this. This is sensitive data, the user certainly wouldn't want just anybody to know this, but the SCWApp shouldn't completely hide and protect it as it might be useful. So we wish to let the user have control over it. This is where custom permissions come in.

The SCWApp creates a custom permission, DevTrainer requests this permission and the user can decide whether he wants to allow this or not. This is a common practice and a good way to restrict access to white-listed applications.


Unfortunately, there are some unintuitive behaviors around custom permissions which makes them risky from a security standpoint. Concrete, custom permissions can be defined by any app at any time, and "first one wins", and this strategy comes with some consequences.

For the following scenario, we define two app profiles which we introduced above (all of these applications are fictional for demonstrative purposes):

 1. SCWApp: the app that defines a custom permission and defends a component using this permission.

 2. DevTrainer: this app defines the same permission as SCWApp and declares to the user that it wishes to hold this permission.

This is a common scenario coined the Peer Apps Case. If the DevTrainer app was just a plugin for the SCWApp it would not have to define the custom permission. The assumption, in this case, is that SCWApp would be installed before DevTrainer and no unexpected behavior will happen. If somehow the user does install DevTrainer first, the user is not informed about the request for the permission. If the user then later installs SCWApp, DevTrainer is not retroactively granted the permission, so the DevTrainer app's attempts at using the secured component will fail.

This is where the Peers App Case comes in. In some cases, you cannot expect one app to be installed before the other. Say if Facebook and Twitter both want to use each other's components, they have to define each other's custom permissions.

However, this is where it gets tricky. If the DevTrainer app is installed first, the user is not informed about its request for the custom permission. At this point, even though the user was not informed, DevTrainer holds the custom permission and can access the secured component.

It gets even trickier. The DevTrainer app can change the permissions protection level. Android does not use the defender's protection level but the protection level that is defined first, meaning whichever app was installed first can define it. This means that if DevTrainer changes the permission level to normal, then any future apps that request this permission will not have to be confirmed by the user but are automatically granted access.

This scenario was inspired by the explanation for this problem found on the cwac-security github.

The "first one wins" strategy has some dangerous consequences and not knowing its behavior might lead the developer to make security decisions based on untrusted input and allow unintended apps to access sensitive data or protected services. To learn more about avoiding security decisions via untrusted input, visit our platform. This behavior was changed as of Android 5.0 (Lollipop). But since currently, more than 22% of Android devices are still running a lower version of Android it is important to mitigate the risks of the original behavior in your app. Check if the permission has already been defined at the first run of your app and take appropriate actions if this is the case to resolve any security risks.

Good luck coding, and see you next week!

- Pieter