How deep links work in Nigerian fintech apps
Mobile operating systems route URLs to apps using one of two mechanisms. The older mechanism is custom URL schemes: an app registers a scheme like cowrywise:// or kuda:// and any URL starting with that scheme opens the app. The newer, more secure mechanism is App Links (Android) and Universal Links (iOS): the app registers ownership of an HTTPS domain by hosting a verification file, and URLs on that domain open the app directly when the operating system verifies domain ownership.
The security difference is critical. Custom URL schemes are vulnerable to scheme hijacking — any app on the device can claim the same scheme, causing the OS to offer the user a choice of which app handles the link. App Links and Universal Links can only be claimed by an app that can prove ownership of the domain by hosting the verification file. Nigerian fintech apps that still use custom URL schemes for payment flows or OAuth callbacks are vulnerable to deep link interception on any Android device where an attacker's app is installed.
1. Custom URL scheme hijacking
We enumerate the deep link schemes registered by the target fintech app by decompiling the APK and inspecting the Android manifest. For each scheme, we create a proof-of-concept app that declares the same scheme and registers it with a higher priority. We then trigger a deep link on a test device with both apps installed and observe whether the OS routes the deep link to our proof-of-concept app, the legitimate app, or shows a disambiguation dialog.
For payment flows, the hijack is immediately consequential: a user who taps a payment link and has an attacker's app on their device can be sent to a spoofed payment confirmation screen that collects their PIN. The attacker's app does not need to actually process a payment — it only needs to collect the PIN and the payment parameters before closing and telling the user the payment failed. The attacker then uses the captured PIN against the legitimate app's API.
2. OAuth redirect interception in bank account linking
When a user links their bank account through an open banking aggregator, the flow goes: user opens fintech app, fintech app opens bank's OAuth page in a browser, user authenticates at bank, bank redirects back to fintech app via a deep link containing the authorization code. This authorization code is the key to the user's bank account data.
If the fintech app registers the OAuth redirect URI as a custom URL scheme, an attacker's app that claims the same scheme receives the authorization code instead of the legitimate app. The attacker's app silently sends the code to a server, exchanges it for an access token, and has obtained a live connection to the user's bank account — all while the user's legitimate app shows a timeout or error screen. We test every OAuth flow for reliance on custom scheme redirects and recommend migration to App Links with verified domain ownership.
3. Deep link parameter injection
Even when deep links are delivered to the correct app, the parameters within the deep link can be attacker-controlled. We test every deep link handler for parameter injection. For a payment request deep link, the parameters typically include a recipient identifier and an amount. We test whether the app validates these parameters server-side before presenting the confirmation screen, or whether it trusts the client-received parameters and displays whatever amount was in the link — allowing an attacker to craft a payment link for a different amount than the displayed value.
# Craft a malicious payment deep link with manipulated amount
# Legitimate link:
myfintech://pay?to=user_xyz&amount=5000
# Attacker crafts link showing 500 but actually requesting 50000
# If the app displays the amount from the URL parameter without server validation:
myfintech://pay?to=attacker_account&amount=50000&display_amount=500 4. Universal Link and App Link configuration validation
For apps that have migrated from custom schemes to App Links or Universal Links, we validate the configuration is correctly implemented. Common configuration failures include: the assetlinks.json file (Android) or apple-app-site-association file (iOS) is not served with the correct content type, the file lists an old app signing key that no longer matches the current app, or the file is served behind authentication — making it inaccessible to the OS verification service. Any of these failures causes the OS to fall back to treating the link as a custom scheme, reintroducing the hijacking risk.
5. Deep link in background app state exploitation
We test what happens when a deep link is delivered to a fintech app that is in the background with an active authenticated session. In some implementations, a deep link delivered while the user is logged in bypasses the PIN or biometric confirmation that would normally be required to initiate a transaction. An attacker who can cause a user to tap a crafted deep link — sent via WhatsApp, SMS, or email — while the app is in a logged-in background state can trigger a pre-configured transaction without any additional authentication from the user.
OAuth bank linking redirect code intercepted via custom URL scheme on Android
During a penetration test of a Nigerian lending platform, we identified that the OAuth redirect URI for the bank account linking flow was registered as a custom URL scheme: lendingapp://oauth/callback. We created a proof-of-concept Android app that declared the same scheme in its manifest. After installing both apps on a test device, we initiated the bank account linking flow in the legitimate app. When the bank redirected back with the authorization code, the Android OS showed a disambiguation dialog. When we selected our proof-of-concept app, we received the authorization code in our app's intent extras. We exchanged this code with the aggregator's token endpoint and obtained a valid access token for the test user's linked GTBank account. The legitimate lending app received no callback and displayed a generic error. Fix priority: critical. Remediated by migrating the OAuth redirect URI to an App Link with a verified assetlinks.json file hosted on the platform's own domain.
Does your Nigerian fintech app use deep links for payment flows, bank linking, or QR codes? Book a mobile security assessment that covers your deep link attack surface.
Book a Mobile Deep Link Security AuditFrequently asked questions
What is a deep link in a Nigerian fintech app?
A deep link is a URL that opens a specific screen or flow inside a mobile app. In Nigerian fintech apps, deep links are used for payment requests (someone sends you a payment link that opens the payer's app on the confirm payment screen), bank OAuth redirects (after a user links their bank account through Mono or Okra, the bank redirects back to the app via a deep link), and in-app promotions. Deep links bypass the app's normal navigation and land the user directly in a specific flow, which means they also bypass the security checks that normally precede that flow.
What is the difference between a custom URL scheme and an App Link?
A custom URL scheme (e.g., myfintech://pay?amount=5000) is registered by the app and claimed by any app on the device that declares the same scheme. If a malicious app on the same device declares the same scheme, it intercepts the deep link. An App Link (Android) or Universal Link (iOS) uses a verified HTTPS URL (e.g., https://myfintech.ng/pay?amount=5000) that is cryptographically bound to the app through a file hosted on the domain. App Links and Universal Links are significantly more secure than custom URL schemes and should be the only mechanism used for security-sensitive flows.
Can deep link hijacking happen in production on real devices?
Yes. On Android, installing a malicious APK that declares the same URL scheme as the target fintech app causes the Android OS to show the user a disambiguation dialog when a matching deep link is triggered. If the user taps the malicious app — or if the attacker's app is set as the default handler for that scheme — the deep link is delivered to the attacker's app instead of the legitimate fintech app. No root or special privileges are required on the attacker's device.
Related reading
Blog: Flutter app penetration testing · React Native security · Open banking aggregator security
Services: Penetration testing · API security