Skip to content

Back to the catalog

Android deep link vulnerabilities: how intent filters lead to account takeover | Oversecured Blog
oversecured.comarticle

Android deep link vulnerabilities: how intent filters lead to account takeover | Oversecured Blog

Oversecured's article on Android deep-link vulnerabilities covers five patterns: custom scheme hijacking, open redirect into WebView, limited and full intent redirection, and domain takeover via an expired whitelist entry. It shows bypass payloads, intent selector abuse, and the HierarchicalUri reflection bypass. It also compares what SAST and DAST can find and gives a checklist for pentesters.

TL;DR Explains how Android intent filters, WebView URL checks and intent redirection chain into account takeover, and what SAST versus DAST detects.
Document

What it is

Oversecured's write-up of five Android deep-link vulnerability patterns seen in production apps, with a pentest checklist. The vendor frames it around its own SAST/DAST scanner, but the technical detail stands on its own. Its central claim is that the damaging findings are chains of three or four steps, not single flaws.

How it works

Intent filters are not an access control. An intent:// URL with a selector can target a component directly and override filter matching:

intent://open#Intent;scheme=myapp;component=com.victim/.InternalActivity;action=android.intent.action.SEND;SEL;action=android.intent.action.VIEW;end

Passed to startActivity(), this launches InternalActivity with a SEND action even though the filter matched VIEW. Chrome blocks selectors. Most WebView implementations and Firefox do not.

The five patterns:

  • Custom scheme hijacking. Any app can claim myapp://, and a malicious app can register a higher priority (up to 999). The main risk is an OAuth callback (myapp://oauth?code=xyz) or any token delivered by deep link, such as password reset or magic login links.
  • Open redirect into WebView. startsWith("https://trusted.com") and contains("trusted.com") checks fail against https://trusted.com@attacker.com/ and https://trusted.com.attacker.com/steal. The page says a major Asian super-app's routing library had a startsWith check with three bypass variants.
  • Limited intent redirection. A user taps an intent:// link inside a WebView, the app calls Intent.parseUri() and startActivity(), and a non-exported internal Activity launches. A deep link is not needed as the entry point. Certain flags and data types are blocked.
  • Full intent redirection. An exported activity takes a nested Intent from extras and passes it to startActivity(). The attacker controls flags, including FLAG_GRANT_READ_URI_PERMISSION, which reaches non-exported Content Providers and enables file exfiltration.
  • Expired whitelist domain. The Android whitelist check is correct, but one listed domain has lapsed. The attacker registers it, the app loads it and sends authorization headers, and the attacker captures a valid token.
flowchart TD
    A[Exported + BROWSABLE + no validation] --> B[Custom scheme claimed]
    A --> C[URL param into WebView]
    A --> D[Nested Intent in extras]
    C --> E[intent:// link in WebView]
    E --> F[Intent.parseUri to startActivity]
    D --> G[startActivity with attacker flags]
    F --> H[Internal Activity reached]
    G --> I[Provider read / file exfil]
    B --> J[OAuth code or token intercepted]

Preconditions / Affected

  • The most common risky setup is android:exported="true" plus the BROWSABLE category plus no parameter validation.
  • Scheme hijacking on OAuth needs a flow without PKCE. Android 12+ sends unverified links to the browser by default, but the page says the risk then shifts to OAuth flows. Account takeover is "possible but not guaranteed".
  • The HierarchicalUri bypass lets a crafted android.net.Uri subclass, built by reflection, return legitimate.com from getHost() while webView.loadUrl() goes to attacker.com. It needs a second app on the device that passes the Uri object. It affected Android before 12. From API 28 internal interfaces are restricted, though RestrictionBypass can circumvent that.
  • App Links remove scheme hijacking but can fail through a misconfigured assetlinks.json, wrong SHA-256 fingerprints, or silent verification failure that falls back to the browser.

What to do

Audit for these:

  • Every exported Activity with BROWSABLE.
  • URL parameters flowing into WebView. Test for whitelist bypasses, not just whether a check exists.
  • getParcelableExtra() on exported components, where the Parcelable is an Intent passed straight to startActivity().
  • Intent.parseUri() calls downstream of WebView URL loading.
  • OAuth callbacks: use verified App Links, never custom schemes, and check for PKCE.
  • Domains in any whitelist: monitor their registration status, since code review cannot show expiry.

The page maps these issues to OWASP Mobile Top 10 M3 and M8, and points to MASTG "Testing Deep Links".

Caveats

  • SAST flags contains/startsWith host checks and traces data flow to sinks. It cannot see expired whitelist domains, server-side redirect token leaks, or which app handles a scheme at runtime.
  • Backend-dependent issues are hard to detect automatically, including by DAST. The vendor says it is still working on this.
  • The page gives no CVE ids, and its real-world examples are unnamed.

Organisations named here

  • App Links
  • custom scheme hijacking
  • deep link hijacking
  • HierarchicalUri bypass
  • intent selectors
  • OWASP MASTG
  • OWASP Mobile Top 10
  • PKCE

Technologies named here

  • SAST
  • DAST
  • Firefox
  • Android
  • OAuth
  • Chrome
  • Oversecured
  • A major Asian super-app (routing library with bypassable startsWith check; intent:// link chain in WebView)
  • Android 12+ (unverified links default to the browser)
  • Android versions before Android 12 (HierarchicalUri bypass)
  • Android WebView
  • assetlinks.json
  • Oversecured scanner
  • OWASP Mobile Top 10
  • PKCE
  • RestrictionBypass

Techniques named here

  • Open redirect
  • Intent Redirection
  • App Links verification bypass
  • Custom URI scheme hijacking
  • Domain takeover via expired whitelist entry
  • Full intent redirection
  • HierarchicalUri bypass
  • Intent selector bypass of intent filters
  • Limited intent redirection via WebView
  • Open redirect via deep links
  • Taint analysis with runtime confirmation