← Back to all reports

Ride-Hailing App Deep Link SSRF to One-Click Ride Booking

Reported Mar 31, 2026
Severity High
Platform Android
Vulnerability Class Deep Link SSRF (CWE-918)
Target Type Ride-Hailing
Impact One-click ride booking on victim accounts

The Risk

An attacker could trick any user of a ride-hailing app into booking a real ride, with a real driver dispatched, just by opening a single link. The link could arrive in a text, an email, a QR code, or even fire automatically from another app on the phone with no tap at all. The same flaw also let the attacker hit any other action on the user's account, like changing the default payment method or removing security keys, all under the user's own login.

The Vulnerability

The Android app exposed a deep link handler that accepted attacker-controlled JSON describing a backend API request. The handler took a path and a body from the JSON, validated the path against a domain allowlist, then fired an authenticated POST to that path on the company's own API with the victim's bearer token automatically attached.

Relative paths bypassed the allowlist entirely. The validator parsed the path with Android's URI parser and pulled the host. For a relative path starting with /, the host came back as null. The validator treated null as allowed:

// Simplified validator logic
if (path.startsWith("/")
    || Uri.parse(path).getHost() == null) {
    return true;  // allowed
}

The relative path then resolved against the live API host. The standard HTTP interceptor that attached the bearer token to every authenticated call ran as normal, sending the attacker's chosen body to the attacker's chosen path on the user's behalf.

Compounding the issue, the ride tokens needed to actually book a ride (a search token and a price-lock hash) were not user-bound. Tokens generated by the attacker's own account from their own device worked when used inside any other user's authenticated request.

The Attack

Tested end to end with two separate test accounts on different devices and different phone numbers. Real rides were created, real drivers were dispatched, and rides entered the "waiting for driver confirmation" state. All test rides were cancelled immediately.

  1. The attacker calls the ride-options endpoint from their own account to get a search token and price-lock hash for a chosen route
  2. The tokens are embedded into a JSON payload of the form {"path":"/rides/order/create","body":{...pickup, dropoff, payment, tokens}}
  3. The JSON is URL-encoded into a deep link, for example app://action/blocksModal?postRequest=<payload>
  4. The victim opens the link. A small landing page auto-redirects to the app via the Android intent scheme. This works even from cold start
  5. The app validates the path. The relative path passes. The interceptor attaches the victim's bearer token. The POST fires
  6. The attacker's body plus the victim's auth equals a ride booked on the victim's account

Delivery channels confirmed working

  • Link click in Chrome, SMS, email, or messaging apps. The page auto-redirects via the Android intent scheme
  • QR code scanned by the victim. The browser opens, then redirects to the app
  • Co-installed Android app firing the deep link intent programmatically with zero permissions and zero user interaction. No click required at all

Broader attack surface

The relative-path bypass was not specific to ride booking. Anything reachable on the company's authenticated user API was reachable through this primitive: deleting saved payment instruments, changing the default payment method, updating profile info, initiating phone-number changes, removing passkeys, binding external auth providers, and many other state-changing endpoints.

Each request also automatically appended the victim's live GPS coordinates, user ID, device ID, and session ID as query parameters via the standard request decorators, leaking real-time location to the attacker's server on every fire.

The Impact

Confirmed against two separate live accounts on real devices:

TestResult
Ride booking on victim account A (suburb to suburb)Real driver dispatched, ride entered waiting state, cancelled
Ride booking on victim account B (different device, different number)Real driver dispatched, ride entered waiting state, cancelled
Ride tokens reused across accountsTokens generated by attacker account accepted in victim requests
Live GPS leakCoordinates appended to every SSRF'd request

At scale, an attacker who collected even a single click from victims could rack up unauthorized rides, harvest live location data, or quietly modify account settings without any password prompt. Because the deep link could be fired without any user interaction by a co-installed app, anyone with a malicious app already on the phone could trigger this against the user silently.

Remediation

  • Reject relative paths in the deep link handler outright. Require an absolute URL and validate the parsed host against the allowlist
  • Treat null hosts as denied, not allowed. Default to deny
  • Bind ride tokens (search token, price-lock hash) to the user account that generated them, not just to the route
  • Do not accept attacker-controlled JSON describing API requests through deep links. Drive specific user actions through specific deep link intents with typed parameters
  • Audit other deep link handlers in the app for the same pattern of forwarding attacker-controlled payloads to the authenticated backend