Skip to content

Validate deep-link args when resolving the start location#200

Open
mbarta wants to merge 2 commits into
mainfrom
security/validate-deeplink-start-location
Open

Validate deep-link args when resolving the start location#200
mbarta wants to merge 2 commits into
mainfrom
security/validate-deeplink-start-location

Conversation

@mbarta

@mbarta mbarta commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Problem

NavigatorHost.ensureDeeplinkStartLocationValid() validates the start location only inside the deepLinkExtras intent extra (android-support-nav:controller:deepLinkExtras).

AndroidX NavController also reads a second extra — deepLinkArgs (android-support-nav:controller:deepLinkArgs) — and merges it over deepLinkExtras when assembling each destination's arguments (arguments.putAll(globalArgs) followed by arguments.putAll(deepLinkArgs[index]), so the later write wins). Because an exported Activity's launch intent is externally controllable, a location (or any other argument) supplied via deepLinkArgs overrides the validated value and becomes the navigator's start destination — loading an unvalidated URL into the host's WebView.

Fix

These android-support-nav:controller:* extras are only ever produced by NavDeepLinkBuilder from within the app, so the fix verifies the launching intent's origin before honoring them — the same direction AndroidX is taking upstream (see aosp/4111813 — "Verify intent origin before handling explicit deep links").

ensureDeeplinkStartLocationValid() now:

  • Trusts intents the app produced itself and leaves them untouched. An intent is trusted when its calling package (or referrer authority) is this app's package; intents carrying the attacker-settable EXTRA_REFERRER / EXTRA_REFERRER_NAME are never trusted.
  • Sanitizes every other intent (rather than dropping it): each deepLinkArgs per-destination bundle is emptied so it can't override the validated start location, and a deepLinkExtras start location whose host doesn't match the configured start host is reverted to the configured start location.

This keeps legitimate same-host start locations working while preventing an external intent from steering the navigator to an arbitrary URL, and it no longer scrubs deep links the app created itself.

Tests

NavigatorHostTest covers:

  • a trusted, self-originated intent is left untouched;
  • an untrusted intent with an off-host start location is reverted to the configured one;
  • an untrusted intent with a same-host start location is preserved;
  • an untrusted intent's deepLinkArgs are emptied;
  • a spoofed-referrer intent is treated as untrusted.

🤖 Generated with Claude Code

NavigatorHost.ensureDeeplinkStartLocationValid() validated only the `location`
inside the deepLinkExtras intent extra. AndroidX NavController also reads a
separate deepLinkArgs extra and merges it over deepLinkExtras when building the
start destination's arguments (last write wins), so a value supplied via
deepLinkArgs on an externally-launched intent could override the validated
start location.

Neutralize the externally-supplied deepLinkArgs by replacing each
per-destination argument bundle with an empty one, in addition to the existing
deepLinkExtras host validation. This is a rewrite (not a removal), so the
deepLinkIds navigation path and the validated start location are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mbarta mbarta marked this pull request as draft June 18, 2026 15:15
@mbarta mbarta self-assigned this Jun 23, 2026
@mbarta mbarta requested review from jayohms and jhutarek June 23, 2026 12:37
@mbarta mbarta marked this pull request as ready for review June 23, 2026 12:37
Trust intents the app produced itself (verified via the calling package or
referrer, rejecting the spoofable referrer extras) and leave their deep-link
extras untouched. Any other intent keeps the existing sanitization: empty
deepLinkArgs and revert an off-host start location to the configured one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant