Navigating the Depths of Deep Link Security

What is a deep link?

Deep linking is the practice of embedding hyperlinks to specific content within a mobile application. This technique directs users to a particular location within an app rather than just opening it to its main screen. The most common use case of deep links is for mobile marketing and advertising campaigns, where a user is directed to a specific product or service within an app.

Deep links are URLs that are specific to the content within an app. They can look like regular URLs starting with “http” or “https,” or start with the app’s custom scheme, such as “myapp://”. When a user clicks on a deep link, it opens the app and takes them directly to the linked content.

Deep link reading is the process of reading and interpreting deep links. Mobile operating systems like iOS and Android have built-in mechanisms to handle deep links, but apps must be set up to handle them properly. Developers need to register their app to handle specific URL schemes and set up rules for how those URLs are handled within the app.

Deep linking can drive increased user engagement, retention, and conversions by directing users to specific content within an app. Additionally, deep linking can help improve app discoverability by allowing users to find and access specific content within an app without navigating the entire app. In this blog, we are going to discuss specifically about Android deep links.

Deep link formats

  1. Scheme URLs (Custom Scheme URLs)
  2. App Links (Android App Links)

Scheme URLs

In this iteration of deep links, any application can register any scheme, host and path.

This means that there’s no mechanism to ensure, for example, that all deep links with the fb:// scheme are handled by the Facebook app.

If a user clicks on a deep link, Android starts by checking which of the applications installed on the device have registered it:

  • If only one application exists, Android will automatically open the deep link with that application
  • If more than one application exists, Android will check if any of them have previously been set as the “preference” – if yes, Android will open the link with that application
  • If there is more than one application and none of them have ever been set as the preference, Android will prompt the user to choose between the apps

Note that if the user clicks “Always” on this prompt, the chosen application becomes the preference, and the prompt will not be shown again.

App Links

Android App Links, available on Android 6.0 (API level 23) and higher, are web links that use the HTTP and HTTPS schemes and contain the autoVerify attribute. This attribute allows your app to designate itself as the default handler of a given type of link. So when the user clicks on an Android app link, your app opens immediately if it’s installed.

When implemented correctly, app links prevent other apps from claiming a link by establishing trust that your app has been approved by a specific website to open links for the associated domain automatically.

Exploring deep link security through contexts

Various contexts specific to scheme URLs and app links determine whether or not users will be prompted with a dialogue after clicking a deep link. App Links always have at least one matched app, the mobile web browser(s).

In the following tables, “user preference” refers to the case where the deep link has been triggered earlier and whether or not the user selects “Always” on the resulting prompt. If yes, the chosen application becomes the preference, and the prompt will not be shown again.

On Android 11 (API level 30) and lower, the system doesn’t verify your app as a default handler unless it finds a matching Digital Asset Links file for all the app link hosts you define in the manifest.

Table 1: Contexts (Android 11 & lower)

Starting in Android 12 (API level 31), a generic web intent resolves to an activity in your app only if your app is approved for the specific domain in that web intent. If your app isn’t approved for the domain, the web intent resolves to the user’s default browser app instead. The contexts for handling custom scheme URLs remain the same from Android 12 onwards.

Table 2: Contexts (Android 12 & higher)

Analyzing registered app links and verification status

In order to check the current system settings for link handling. Use the following command to get a listing of existing link-handling policies for all apps on your connected device:

adb shell dumpsys package domain-preferred-apps

Image: App link handling

This listing indicates which apps are associated with which domains for that user:

  • Package – The application package name as declared in its manifest or the application ID specified in your project’s build.gradle file.
  • Domains – This shows the full list of hosts whose web links this app handles, using blank spaces as delimiters.
  • Status – Shows the current link-handling setting for this app. An app that has passed verification and whose manifest contains android:autoVerify="true", shows a status of always. The hexadecimal number after this status is related to the Android system’s record of the user’s app linkage preferences. This value does not indicate whether verification succeeded. If the application has not passed verification and the user has not explicitly marked an application as “preferred”, then the status would indicate ask. This means that the user will be prompted with a dialogue to choose between two or more applications that have registered the app link.

Note: If a user changes the app link settings for an app before verification is complete, you may see a false positive for a successful verification, even though verification has failed. This verification failure, however, does not matter if the user explicitly enabled the app to open supported links without asking. This is because user preferences take precedence over programmatic verification (or lack of it). As a result, the link goes directly to your app without showing a dialogue, just as if verification had succeeded.

Ensuring deep link security with app link verification

Image: App link verification process in Android

Android App Links use the Digital Asset Links API to establish trust that your app has been approved by the website to automatically open links for that domain. If the system successfully verifies that you own the URLs, the system automatically routes those URL intents to your app. Android App Links are secure i.e. no unauthorized app can handle your links.

To verify that you own both your app and the website URLs, complete the following steps:

  1. Add intent filters that contain the autoVerify attribute. This attribute signals to the system that it should verify whether your app belongs to the domains used in your intent filters.
  2. Declare the association between your website and your intent filters by hosting a Digital Asset Links JSON file at the following location: https://**domain.name**/.well-known/assetlinks.json

Digital asset links file (DAL)

Digital Asset Links JSON file must be published on your website to indicate the Android apps that are associated with the website and verify the app’s URL intents. The assetlinks.json file uses the following fields to identify associated apps:

  • package_name: The application ID specified in your app’s build.gradle file.
  • sha256_cert_fingerprints: The SHA256 fingerprints of your app’s signing certificate. This field is an array that supports multiple fingerprints, which can be used to support different versions of your app, i.e. debug and release builds.

You can use the following command to generate the fingerprint via the Java keytool:

keytool -list -v -keystore my-release-key.keystore

If you’re using Play App Signing for your app, then the certificate fingerprint produced by running keytool locally will usually not match the one on users’ devices. You can verify whether you’re using Play App Signing for your app in your Play Console developer account under Release > Setup > App Integrity. If yes, then you’ll also find the correct Digital Asset Links JSON snippet for your app on the same page.

Following is an example of an assetlinks.json file that grants link-opening rights to a com.example.testapp Android app:

In case you want to test the app link verification using your app’s debug build in Android Studio, follow the below steps to retrieve the sha256 fingerprint:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.testapp",
    "sha256_cert_fingerprints":
["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

Click on Gradle in the Android studio from the top right corner. You will see your package there. Go to package -> Tasks -> android -> signingReport.

Image: Run gradle signingReport task

After successful execution, fingerprints generated using multiple hashing algorithms will be printed on the console. Copy the SHA-256 fingerprint into your DAL file i.e. assetlinks.json

Image: Run gradle signingReport task

App link auto verification

When android:autoVerify="true" is present in at least one of your app’s intent filters, installing your app on a device that runs Android 6.0 (API level 23) or higher causes the system to automatically verify the hosts associated with the URLs in your app’s intent filters.

The system’s auto-verification involves the following:

  1. The system inspects all intent filters that include any of the following:
    • Action: android.intent.action.VIEW
    • Categories: android.intent.category.BROWSABLE & android.intent.category.DEFAULT
    • Data scheme: http or https
  2. For each unique hostname found in the intent filters, Android queries the corresponding websites for the Digital Asset Links file at https://**hostname**/.well-known/assetlinks.json

Digital Asset Links API

For each website, use the Digital Asset Links API to confirm that the Digital Asset Links JSON file is properly hosted and defined:

https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://domain.name:optional_port&relation=delegate_permission/common.handle_all_urls

Replace the value of the source.web.site parameter in the above URL to check if the DAL JSON file is properly hosted for your app link:

https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://akhilari7.github.io&relation=delegate_permission/common.handle_all_urls

If the DAL file for your website is valid, you should see a response similar to the following:

Image: Valid DAL file

If the DAL file is invalid, the error message in the debugString field will reveal information about the misconfiguration.

Image: Invalid DAL file

Please note that the Digital Asset Links API will only validate the structure of the DAL file and not whether the contents of the DAL are correct, e.g. packageName and the signing certificate’s sha256Fingerprint.

After confirming the website(s) to be associated with your app and ensuring that the hosted JSON file is valid, install the app on your device. During installation, the sha256 hash of the app’s signing certificate will be calculated and matched with the fingerprint specified in the DAL file. It usually takes up to 20 seconds for the asynchronous app link verification process to be completed.

Success conditions:

The app link verification will fail if any of the following conditions are not met:

  • The assetlinks.json file should be served with content-type application/json
  • The assetlinks.json file must be accessible over an HTTPS connection, regardless of whether your app’s intent filters declare HTTPS as the data scheme
  • The assetlinks.json file must be accessible without any redirects (no 301 or 302 redirects)
  • If your app links support multiple host domains, then you must publish the assetlinks.json file on each domain
  • The website hosting the DAL is not accessible over the internet. It is advised not to publish your app with dev/test URLs in the manifest file that may not be accessible to the public, e.g. URLs that are accessible only with a VPN

Verify link associations

adb shell dumpsys package domain-preferred-apps

On successful app link verification, running the above adb command should return the status of always for the domains associated with your application. If the status is not always, it means the app link verification has failed, and your app is not the designated application for the registered domain.

Note: If a user changes the app link settings for an app before verification is complete, you may see a false positive for a successful verification, even though verification has failed. This verification failure, however, does not matter if the user explicitly enabled the app to open supported links without asking. This is because user preferences take precedence over programmatic verification (or lack of it). As a result, the link goes directly to your app without showing a dialogue, just as if verification had succeeded.

Common errors discovered while implementing app link verification consisted of:

  • Not creating the associate DAL file
  • Registering the App Link with a protocol that doesn’t match the DAL file (HTTP vs HTTPS)
  • Invalid or incorrectly configured associate file
  • Invalid or incorrect configured intent filter in the manifest file

Attack Vector 1: Use of custom schemes and unverified app links

Custom scheme URLs are the first iteration of deep links and are still widely used to this date. These types of deep links are inherently vulnerable to deep link hijacking as there is no mechanism to verify the designated application for handling a custom scheme URL.

A study conducted in 2017 concluded that more applications utilized custom scheme URLs than app links and the applications that did use app links rarely verified their app links correctly!

Applications that register deep links with custom schemes are inherently unsafe from the potential of deep link hijacking.

The fact that any application can register any Scheme URL, along with the use of deep links with custom schemes or improper implementation of App Links can make applications vulnerable to deep link hijacking due to “Deep Link Collision”. Why is this an issue?

Users are shown a prompt when multiple apps have registered the same scheme. User prompt can be skipped in the following scenarios:

  • If the malicious app is installed before the original app
  • If the malicious app tricked users to set preference
Image: Deep link collision

The risk of deep link hijacking is applicable for both custom scheme URLS, e.g. myapp://link and unverified app links, e.g. https://app.com in Android 11 and below. In both of these cases, relying on end-users as the sole security defense is risky since they might fail to perceive the nature of an attack.

The handling of unverified app links is more robust from a security perspective in Android 12 and above. Unverified app links, i.e. web links, are opened in the default browser without prompting the user with a choice of apps that have registered this app link.

Attack Scenario

Now that we have looked at how including custom scheme URLs and/or unverified app links makes the application vulnerable to deep link collision/hijacking, let’s dive into a scenario of sensitive information being captured via deep link hijacking. In this case, deep links are used to transfer sensitive data, such as authentication tokens; an attacker can use link hijacking and attempt to intercept this data.

The target application has registered an app link but has not implemented link verification. Another application can be created that handles the same app link and intercepts intents. Assuming that the malicious application is installed on the device, the user will be prompted with both applications when the app link is triggered.

Assume a scenario in which the user has a car rental app installed on their device named “Foobar car rental”. This application has registered an app link for listening to the intent received when the password reset link is triggered by the user. The domain akhilari7.github.com of this app link is not verified, however, so another application installed on the device that has registered the same app link can intercept the intent data.

The following image shows the manifest file of the foobar application. It includes an intent filter with the android:autoVerify attribute and specifies the app link http://akhilari7.github.com

Image: Manifest file belonging to the foobar car rental app

Consider that the application emails a password reset link to the user when the user initiates a password reset request. This link contains a reset token that identifies and authenticates the correct user that requires to change/reset their password.

If the app link http://akhilari7.github.com was verified, the user would be seamlessly redirected to the password reset activity of the application without any prompt/dialogue upon clicking the link.

However, due to the app link http://akhilari7.github.com not being verified, Android would prompt the user with a dialogue to choose between the apps that handle this app link. If the user selects the malicious app deep link hijacker in the below image, then this application can intercept the intent data and capture the authentication token of the user.

In the following example, the malicious application simply displays the intercepted app link/intent data containing the auth token on the screen. The hijacker application can also exfiltrate the captured data to an attacker-controlled server.

Apart from the interception of sensitive information, other attack scenarios associated with deep link hijacking include phishing and traffic hijacking.

Phishing

Imagine that a user installs a game application on their Android phone. Whenever the user opens the app, they just see the game but, in fact, during installation, this application registered a deep link that “belongs” to a banking app – acmebank:// – which just so happens to be the user’s bank.

One day, this user happens to click on the same deep link registered by the “malicious” game app – this isn’t strange since it’s a valid deep link used by the actual ABC Bank.

Since the user doesn’t yet have the acmebank application installed on their phone, the OS will automatically open the link with the game app. However, now, instead of showing the regular game UI, this malicious app displays a login screen that looks exactly like the login screen for acmebank.

The malicious application can potentially trick the user into entering their acmebank credentials on this login screen.

Traffic Hijacking by competitor applications

Back in 2017, a study, “Measuring the Insecurity of Mobile Deep Links of Android” reviewed 160,000+ applications (retrieved from the Play Store) and found many instances of applications that seemed to be registering custom schemes for popular applications in order to boost traffic to their own app.

They found, for example, that google.com is registered by 480 apps from 305 non-Google developers and that google.navigation from Google Maps was hijacked by 79 apps from 32 developers.

In the same study, it was also discovered that a lot of applications register their competitors’ schemes in order to trick users into using their apps:

For example, Careem (com.careem.acma) and QatarTaxi (com.qatar.qatartaxi) are two competing taxi booking apps in Dubai. Careem is more popular (5M+ downloads), and uses scheme careem for many functionalities such as booking a ride (from hotel websites) and adding credit card information. QatarTaxi (10K downloads) registers to receive all careem://* deep links. After code analysis, it was found that all these links redirect users to the QatarTaxi app’s home screen in an attempt to draw customers.

Reference(s): https://people.cs.vt.edu/gangwang/deep17.pdf

https://www.usenix.org/sites/default/files/conference/protected-files/usenixsecurity17_slides_gang_wang.pdf

Preventing Deep Link Hijacking

To prevent the possibility of deep link/app link hijacking in Android 11 and below, the one and only recommendation is to configure app link verification for the app links registered in your application. Verified app links are secure, i.e. no unauthorized app can handle your links.

As of August 2021, only about 6% of Android devices were still using Android 5 (Lollipop) or earlier versions of the OS, which don’t support App Links. So, at this point, there are not many reasons to still use Scheme URLs, which are insecure by design.

App Links can be tricky to verify correctly, but there are some tools that can help with this task.

Google provides a Statement List Generator and Tester. This tool enables you to test if a given site domain grants app deep linking to the app with the specified name and SHA256 fingerprint:

Reference(s):

https://inesmartins.github.io/exploiting-deep-links-in-android-part-4-mitigation/index.html

https://developers.google.com/digital-asset-links/tools/generator

Attack Vector 2: Unsafe processing of data received via deep link intent

Apart from attempting to hijack the deep link, what can attackers do if they trick a user into clicking a malicious deep link?

Text/Content injection

Consider an scenario wherein Acme Bank has both a web and an Android application, and they use deep links to improve the user experience of transitioning between the two.

The developers want to allow the users to view messages in their applications. In order to do that, they use the following deep link:

acmebank://view-message?text=<message>

The Android application takes the message parameter and injects it into a TextView element:

String message = getIntent().getData().getQueryParameter('message')
TextView messageTextView = (TextView)findViewById(R.id.msgTextView);
messageTextView.setText(message);

In this scenario, it’s possible that a malicious user creates a deep link that tricks a victim into completing some sort of action, e.g.:

State-changing actions without user confirmation

In certain scenarios, the application performs an unsafe state-changing action without user confirmation via deep links.

Examples include data modification, making a call, buying a subscription, changing user information, etc. If these actions are triggered via a deep link and do not require additional confirmation from a user, it is possible to perform a CSRF-like attack.

For example, if an app allows authenticated users to change their email through the myapp://user?email=<email> deep link, you can change the victim’s email to your own by making them visit the following page:

In early 2023, such an attack was reported on Instagram for Android. In the affected version of this messaging tool, a user that triggers the forged deep link could execute a turn-off message request deep link without any permission, and an attacker could disable the feature that allows them to receive messages on Instagram. This is because Instagram’s Android app contained a deep link instagram://turn_off_message_requests that could turn off all requests so the user won’t receive messages from anybody, and this deep link executes headlessly, so there is no UI after execution of the deep link.

Another example of this type of attack can be studied from a 2020 HackerOne report for the Periscope Twitter app (a video streaming service). On the Periscope website, when a user clicks a link to follow a user like www.pscp.tv/<user-id>/follow, they would get a prompt/alert whether to follow a person or not, giving us an option, which means CSRF protection is there in Periscope web application. However, in the Periscope Android App, there are some internal deep links by which we can perform Direct CSRF in terms of the following users using internal deep links.

Reference(s):

https://servicenger.com/mobile/instagram-vulnerability-turn-off-message-requests-deeplink/

https://hackerone.com/reports/583987

WebView vulnerabilities

If an app opens a URL in WebView based on parameters from a deep link you can try to bypass URL validation and open arbitrary URLs. This can be used to execute arbitrary JavaScript, steal sensitive data, access arbitrary components, and chain with other weaknesses.

Reference(s):

Extraneous functionality exposed via deep links

Another security report from early 2023 details gaining access to premium features without a subscription.

Twitter launched Twitter Blue in Dec 2022 for Android users, allowing them to change the app icon and undo tweets at any time. Twitter Android’s version number is 9.76.0-release.0 has implemented some deep links for Twitter subscription to perform direct action, and some of those deep links are not being validated or don’t have custom permissions set if the user has a subscription or not, so it is possible to use the change icon, custom navigation, and early access features without a subscription using the below deep links:

twitter://subscriptions/settings/extras twitter://subscriptions/settings/early_access

The extras deep link gives access to change icons and change custom navigation, and early access deep link gives access to features like undo tweets with custom timing.

Reference(s):

https://servicenger.com/mobile/android/access-twitter-blue-features-using-deeplink-without-a-paid-subscription/

Insecure parameter handling

Deep links allows users to provide parameters to an application that can be used as parameters when performing local actions, requests to API, etc. Therefore, if these parameters are not properly validated, an attacker can use them for profit (up to RCE).

For instance, suppose an application opens local files based on http/https URLs by the next flow:

  1. A user sends the link https://website.com/file.pdf
  2. An application parses the URL and retrieves the URL path: file.pdf
  3. An application joins a hard-coded temp folder with file.pdf : /data/data/com.vulnerable-app/temp-files/file.pdf
  4. An application downloads the PDF file from https://website.com/file.pdf and saves it to /data/data/com.vulnerable-app/temp-files/file.pdf
  5. An application opens the downloaded file for a user.

In such case, an attacker is able to rewrite an arbitrary file within the package using path traversal: https://website.com/x/..%2F..%2Fdatabases/secret.db.

Reference(s):

Writeup: RCE IN ADOBE ACROBAT READER FOR ANDROID(CVE-2021-40724)

Subscribe to our Newsletter
Subscription Form
DOWNLOAD THE DATASHEET

Fill in your details and get your copy of the datasheet in few seconds

CTI Report
DOWNLOAD THE EBOOK

Fill in your details and get your copy of the ebook in your inbox

Ebook Download
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download ICS Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Cloud Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download IoT Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Code Review Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Red Team Assessment Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download AI/ML Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download DevSecOps Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Product Security Assessment Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Mobile Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Web App Sample Report

Let’s make cyberspace secure together!

Requirements

Connect Now Form

What our clients are saying!

Trusted by