K1.11.4deep link parameter validationdesignresearch

Unchecked deep-link parameters become an attack surface

Aliases: intent spoofing · URL scheme hijacking · open redirect

What it is

A deep link arrives with a path and parameters. Those fields are not the same as input typed in the UI: they are arbitrary strings from mail, a web page, another app, even a text message. Execute them unchecked and the link is an attack surface—opening a profile that should stay closed, pointing an in-app web view at a phishing page, reading files outside the sandbox, marking an order paid from a forged payment callback. This entry is parameters as untrusted input. It is not whether the landing is home, not the uninstalled fallback, and not how to return to the source.

Why it happens

On many systems anyone can fire a custom URL scheme; the target cannot infer a trusted sender from "a link was tapped." Universal Links raise the bar with domain association, but the query string, path segments, and fragment are still written by the caller. If the app concatenates parameters into SQL, a file path, a WebView URL, or a "mark paid" call, an external string has become an internal command. Typical payloads: change user= to see someone else's profile; change redirect= so authorization finishes on an attacker's page; use file:// or traversal to read local files; forge status=success on a payment return. Checks have to run before route dispatch: host allowlists, typed identifiers, state changes that cannot be written from a link. "It looks like one of our screens" does not make the parameters legitimate; a deep link is supposed to open a real in-app shell.

Studying it

Test the router with a hostile payload list, not only the happy links the product itself emits.

Independent variables: parameter kind (object id, callback URL, status enum, file path), caller (same app, external browser, another app), whether host and type checks run. Dependent variables: unauthorized objects opened, WebView leaving the trusted origin, local files read, payment or session state rewritten by a link.

Intent spoofing, URL-scheme hijacking, and unauthorized origin crossing in the security literature are exactly these payloads. A lab that only generates links from in-app buttons never sees an external caller. Do not read "Universal Links verified the domain" as parameter safety—the host was verified, not the fields in the query string.

Where it stops holding

A guessed identifier on a public read-only deep link (a help article) is usually exposure, not account takeover; checks can be lighter than for writes. A callback from the same app through system association still has to gate state changes on a server-checked one-time token, not on success in the query string. Debug schemes left callable after release are production back doors. Desktop custom protocols have the same shape; mobile adds "any other app can invoke me."

Applying it

  • Treat every deep-link field as untrusted input: object ids must resolve under the current user's rights, callback URLs only to allowlisted hosts, state changes never completed from an enum in the link alone.
  • Load in-app web views only from allowlisted addresses. Reject javascript:, unknown schemes, and path traversal.
  • Verify with three links the product would never emit: someone else's object id, a jump to an external host, a callback that marks an order successful. They should resolve to no access, a refused jump, and an ignored state rewrite. If any of them changes data it should not, the router executed before it checked.

Related

  • Within the group: K1.11.1 A deep link must open the specific screen, not the app's front door · K1.11.2 A missing target app needs a fallback path, not a dead end · K1.11.3 After an inter-app jump, the way back to the source must still exist
  • Adjacent: K8.01 Task continuity · O3.04 Phishing recognition cues
  • Search terms: intent spoofing · URL scheme hijacking · deep link validation

Cards in the same group

Quick Actions

Share

Share this page

ios_share

https://hci.top/en/handbook/K1.11.4