Android’s Accessibility API is an incredibly powerful tool intended for developers to build apps for users with disabilities. The API lets apps read the contents of the screen and perform inputs on behalf of the user, which are essential functions for screen readers and alternative input systems. Unfortunately, these functions are also incredibly useful for malicious apps that want to steal data from users, which is why Google has been cracking down on which apps are allowed to use the Accessibility API. Google has already limited which apps on Google Play can use the Accessibility API, and in Android 13, they’re taking things one step further by heavily restricting API access for apps that the user has sideloaded from outside of an app store.
Android's Accessibility API: A history of open (mis)use
In order to explain what’s changing, it’s important to understand how Android’s Accessibility APIs are currently being used. Google encourages app developers to build apps with accessibility in mind, which is not the same as saying they need to use Android’s Accessibility APIs. Developers can design their apps to be more accessible to users with disabilities without the need for special APIs, but they can only improve the accessibility of their own apps. To help users with disabilities interact with other apps, developers must create what’s called an accessibility service.
An accessibility service is a privileged background service that receives information from the system about certain events, such as when a button has been clicked or a view has been focused. Apps can react to these events to provide different features, such as audible feedback or an alternative way to send an input. For example, a screen reader like TalkBack can read the contents of a dialog on behalf of visually impaired or blind users, while something like Switch Access can press “yes” or “no” on behalf of users with mobility limitations.
Because of the powerful nature of this API, Android requires the user to manually enable accessibility services through an interface in Settings > Accessibility. Before enabling the service, users are warned that they will be granting the application “full control” of their device, including the ability to “view and control [the] screen” and “view and perform actions” on their behalf.
Apps can optionally provide an explanation for what their accessibility service will be used for, but there’s no guarantee that the service will be used in the manner described by the developer. Malware authors take advantage of this to trick the user into enabling an accessibility service. Several infamous phishing and banking trojan campaigns have taken advantage of Android’s Accessibility API to steal data from users. FluBot, for example, texted users a link to an app that impersonated FedEx. After installing the app and enabling its accessibility service, FluBot would collect personal information and attack mobile banking apps. Other trojans, like SharkBot, Xenomorph, BianLian, S.O.V.A, PixStealer, Vultur, and TeaBot, also misuse Android’s Accessibility API.
Why does malware rely on accessibility services?
There are plenty of different kinds of malware for Android out there. But, if we focus on the ones that are crafted to steal your personal data, such as your banking credentials, crypto wallets, social media logins, etc., we find that most of them require using some sort of accessibility permissions. The reasons why they need those are:
1. In order to read the device's screen. Certain pieces of malware abuse accessibility services in order to determine whether certain text is being displayed on the screen, using a technique similar to the one used by screen readers to read text aloud. In this case, the malware may target your banking apps, your crypto wallets, or your social media apps and, if the malware detects they are being displayed on screen, the malware is then able to impersonate the application by either injecting a fake login form through a screen overlay or by switching to some activity present inside the malware's code. The injected form would resemble the appearance of the application it tries to impersonate, in order to lure the user into believing it's the real application being shown. Many times the switch between the real and the fake application is almost imperceptible.
2. In order to prevent the malware from being removed, and in order to impersonate the user (by generating clicks on the screen). The malware also abuses accessibility services in order to produce fake "touches" on the screen and fake button presses, such as the home key. Many pieces of malware do this in order to prevent the user from removing the application that contains the malware, as a defense mechanism. In some cases, this might also be used to install other applications (other malware or unwanted applications) or perform actions without the user's consent, like disabling Google Play Protect, enabling additional permissions for the malware, and changing the default application for calls, messages, etc.
Up until now, the only way to mitigate these kinds of infections is through commercial antivirus services, with Google Play Protect, or by enabling Android's Safe Mode, which disables all applications except the ones that come preinstalled with the device, and which would allow the user to remove the infected application.
-Sergio Castell, mobile security analyst at Riscure
Google has not been oblivious to these threats. Over the years, they have attempted to crack down on apps misusing the Accessibility API.
Cracking down on the Accessibility API
In late 2017, Google sent an email to developers informing them that if their app uses an accessibility service for any reason other than assisting users with disabilities, then they must remove this functionality or face their app’s removal from the Play Store. Google quietly backed off on this threat following backlash from developers, because the policy change would have forced many developers to strip legitimately useful features from their apps. Instead, the company encouraged developers to use Android’s purpose-built APIs in lieu of Accessibility, wherever possible.
Google’s strategy changed in 2021, however. In order to reduce the unnecessary and potentially dangerous uses of Accessibility while preserving legitimate uses, Google updated its app store policy with a new set of requirements for apps that wish to use the APIs. Developers whose apps target Android 12 or later and use the Accessibility API for non-accessibility reasons must complete an extensive permission declaration form and receive approval from Google Play. They must also prominently disclose within their app why they need to access the Accessibility APIs. Finally, they have to require affirmative action from the user to enable the service (before they even get to Android’s built-in dialog). These requirements can be bypassed by apps declaring that they’re an accessibility tool, which is only allowed for apps that are actually designed to assist users with disabilities.
Google also quietly introduced a new feature in Android 12 to warn users about accessibility services they’ve kept enabled. Once in a while, Android will surface a notification titled “check access settings” that reminds the user about accessibility services they’ve enabled. This notification is shown 24 hours after the user enables an accessibility service that hasn’t been declared an accessibility tool and wasn’t installed from a trusted install source. In other words, Android only trusts apps that are legitimate accessibility tools as verified by a trusted app store.
However, a warning that’s shown 24 hours after the user has already enabled the accessibility service may not protect users from malicious apps that act quickly. This is partly why Android 13 places further restrictions on the use of the Accessibility API.
Android 13's restricted access to accessibility services
When the user sideloads an app that has an accessibility service on Android 13, the system may block the user from enabling the accessibility service. If this restriction is applied, the service’s state will be grayed out in settings, and a dialog will appear when tapping the service that says “for your security, this setting is currently unavailable.”
Android 13 applies this restriction to all apps that are installed from a user-acquired APK file, ie. apps that were sideloaded from outside an app store. Google confirmed to Esper that this restriction was designed to not affect apps installed from app stores, both preloaded (like Google Play) or sideloaded (like F-Droid). This is because the company does not want to restrict accessibility API access for all apps that are sideloaded — they just want to restrict access for apps that came from less legitimate sources.
Android determines whether an app came from an app store during the installation process. When an app with an accessibility service is sideloaded by an app that uses the session-based package installation API, this restriction does not apply and the user can enable the accessibility service. This is because this installation method is usually used by app stores to provide a more seamless experience.
When an app with an accessibility service is sideloaded by an app that uses the non-session package installation API, though, the restriction does apply and the user is blocked from enabling the app’s accessibility services. Many apps that let you download and open arbitrary files use this installation method, as it’s easier to simply hand off installation to the system Package Installer, which responds to intents to view and install user-acquired APK files. Apps that are sideloaded via browsers, mail clients, and messaging apps usually use this method, hence they’ll be subjected to Android 13’s restrictions.
Apps can use Android’s new setPackageSource() API to tell the system that the app came from a user-acquired APK via the parameters PACKAGE_SOURCE_LOCAL_FILE or PACKAGE_SOURCE_DOWNLOADED_FILE. This can be used by apps implementing the session-based package installation API to trigger the same behavior when sideloading arbitrary APK files. For example, the Files by Google app uses the session-based API to install apps even though it isn’t an app store. In order to protect users, Files by Google could use the setPackageSource() API to tell the system Package Installer when apps come from user-acquired APKs, thus subjecting those apps to Android 13’s restrictions.
These restrictions are tied to a new permission in Android 13 called ACCESS_RESTRICTED_SETTINGS. This permission controls whether or not the user can enable an app’s accessibility service. When an app has been sideloaded using the non-session method, ACCESS_RESTRICTED_SETTINGS is first set to "deny". After viewing the "restricted setting" dialog, ACCESS_RESTRICTED_SETTINGS is set to "ignore." At this point, the user can go to the app info page for the app in question, tap the three-dot menu, and then tap "allow restricted settings" to unblock access to the accessibility service. The user will then be asked to authenticate themselves, and if they pass, ACCESS_RESTRICTED_SETTINGS will be set to "allow" for the app. The system does not tell the user they can do this, but this could change in future Android 13 builds.
In addition, the ACCESS_RESTRICTED_SETTINGS permission only gates access to accessibility services, but it’s plausible that it could be used in the future to gate access to other sensitive APIs like the notification listener.
In summary, this change affects two different groups of developers in two different ways. Developers who build apps with accessibility services will have to account for the scenario where the system blocks the services. Developers who build apps that use one of Android’s package installation APIs should use the new setPackageSource() API to tell the system where an app that’s being sideloaded came from. Google may provide guidance about this currently undocumented change at its upcoming I/O developer conference, so be sure to watch the event to learn about all the changes in the new OS release. Of course, we will also be documenting all of these changes in our Android 13 deep dive.
Hero image source: rafapress/Shutterstock.com
This article was updated at 1:30 PM PT following publication to note the method to unblock access to restricted settings and to differentiate between the behavior of the ACCESS_RESTRICTED_SETTINGS permission when in "ignore" and "deny" modes.