[SEC-021][All] Validate intent:// browser_fallback_url scheme#3681
[SEC-021][All] Validate intent:// browser_fallback_url scheme#3681kristofnemere wants to merge 1 commit intomasterfrom
Conversation
Reject non-http(s) schemes on the browser_fallback_url extra of intent:// URIs before loading them in CanvasWebView, so a crafted fallback like javascript: or data: cannot execute in the WebView's authenticated context. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🧪 Unit Test Results📊 Summary
Last updated: Tue, 05 May 2026 12:57:16 GMT |
There was a problem hiding this comment.
Review Summary
This is a focused, correct security fix that closes a URL-scheme injection vector in the browser_fallback_url handling path of CanvasWebView.
What the fix does
When an intent: URI cannot be resolved to an installed app, Android's convention allows a browser_fallback_url extra to be loaded instead. Previously that fallback URL was loaded unconditionally, meaning a crafted intent: link could smuggle in a javascript:, file:, or other dangerous scheme through the fallback mechanism. The fix validates the scheme before calling loadUrl.
What's done well
- Uses Android's
Uri.parse()rather thanjava.net.URI, so malformed fallback URLs won't throw — the scheme simply comes backnulland the load is skipped safely. .lowercase()on the scheme ensures the comparison is case-insensitive (e.g.,HTTP://still works).return trueis kept outside the inner scheme check, so the navigation event is still consumed even when the fallback URL is rejected. This correctly prevents the rejected URL from falling through to other handlers.- The change is minimal and surgical — no unrelated refactoring.
Issues found
- Silent failure when fallback URL has an unsafe scheme — see inline comment at line 492. When the scheme is blocked, the user gets no feedback and the navigation silently does nothing. A
Log.w()would make this much easier to diagnose in the field without any user-visible impact.
| val fallbackScheme = Uri.parse(fallbackUrl).scheme?.lowercase() | ||
| if (fallbackScheme == "http" || fallbackScheme == "https") { | ||
| view.loadUrl(fallbackUrl, extraHeaders) | ||
| } |
There was a problem hiding this comment.
When fallbackScheme is neither "http" nor "https", the fallback URL is silently dropped and return true consumes the navigation event — the user gets a broken experience with no indication of what happened. Consider adding a warning log here to aid future debugging:
} else {
Log.w("CanvasWebView", "Blocked unsafe fallback URL scheme: $fallbackScheme")
}This doesn't need to be user-visible, but a logcat entry would make it much easier to diagnose reports of broken intent-fallback navigation in the field.
📊 Code Coverage Report✅ Student
✅ Teacher
✅ Pandautils
📈 Overall Average
|
Test plan:
refs: SEC-021
affects: Student, Teacher, Parent
release note: