Validate deep-link args when resolving the start location#200
Merged
Conversation
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
marked this pull request as draft
June 18, 2026 15:15
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>
Origin signals are too weak to gate on: callingPackage is only set for startActivityForResult launches, and Activity.referrer is backed by the attacker-settable EXTRA_REFERRER. Sanitizing every launching intent is simpler and costs nothing — same-host start locations still pass through, and app-produced deep links keep working. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jayohms
approved these changes
Jul 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
NavigatorHost.ensureDeeplinkStartLocationValid()validates the startlocationonly inside thedeepLinkExtrasintent extra (android-support-nav:controller:deepLinkExtras).AndroidX
NavControlleralso reads a second extra —deepLinkArgs(android-support-nav:controller:deepLinkArgs) — and merges it overdeepLinkExtraswhen assembling each destination's arguments (arguments.putAll(globalArgs)followed byarguments.putAll(deepLinkArgs[index]), so the later write wins). Because an exported Activity's launch intent is externally controllable, alocation(or any other argument) supplied viadeepLinkArgsoverrides the validated value and becomes the navigator's start destination — loading an unvalidated URL into the host's WebView.Fix
ensureDeeplinkStartLocationValid()now sanitizes the launching intent'sdeepLinkArgsin addition to validatingdeepLinkExtras:deepLinkArgsper-destination bundle is emptied so it can't override the validated start location;deepLinkExtrasstartlocationwhose host doesn't match the configured start host is reverted to the configured start location, as before.Sanitization applies to every launching intent. Intent-origin signals are too weak to gate on —
callingPackageis only set forstartActivityForResultlaunches, andActivity.referreris backed by the attacker-settableEXTRA_REFERRER— so there is no reliable way to distinguish app-produced intents from external ones. Unconditional sanitization keeps legitimate same-host start locations working while preventing an external intent from steering the navigator to an arbitrary URL.Tests
NavigatorHostTestcovers:deepLinkArgsare emptied so they can't override the validated start location.🤖 Generated with Claude Code