Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ class WalletWebViewClient(
// Open all foreign web pages and app schemes like "eid" for the AusweisApp
// externally. Only wwWallet code is allowed inside the app.
if (request.url.scheme != baseUrl.scheme || request.url.host != baseUrl.host) {
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The foreign-origin check only compares scheme + host. This treats https://example.com:444/... as same-origin as https://example.com/... (ports are ignored), which can allow loading non-wallet services on the same host inside the privileged WebView. Consider including an (effective) port comparison (or compare authority) when deciding whether a URL is allowed to stay in-app.

Copilot uses AI. Check for mistakes.
// Restrict the schemes we are willing to hand to startActivity.
// Without this guard a page rendered inside the wallet WebView can
// fire arbitrary `intent://`, `content://`, `file://`, or
// `javascript:` URLs at the host activity, a known Android-WebView
// intent-smuggling / deep-link attack surface (CWE-939).
val scheme = request.url.scheme?.lowercase()
val allowed = scheme == "https" ||
scheme == "http" ||
Comment on lines +31 to +33
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request.url.scheme can be null (e.g., for some relative navigations or malformed URLs). With the current scheme?.lowercase() + allow-list, a null scheme becomes allowed == false and the WebView navigation is swallowed (return true), which can break in-wallet navigation unexpectedly. Consider explicitly handling scheme == null (e.g., let super.shouldOverrideUrlLoading handle it, or resolve against baseUrl before applying the allow-list).

Copilot uses AI. Check for mistakes.
scheme == "eid" ||
scheme == "tel" ||
scheme == "mailto"
Comment on lines +32 to +36
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new scheme allow-list is security-critical routing logic but currently has no unit tests. Consider adding tests that exercise shouldOverrideUrlLoading for allowed schemes (http/https/eid/tel/mailto) and denied schemes (intent/content/file/javascript), plus edge cases like null scheme/host and differing ports.

Copilot uses AI. Check for mistakes.
if (!allowed) {
return true
}
activity.startActivity(Intent(Intent.ACTION_VIEW, request.url))
return true
Comment on lines 40 to 41
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startActivity(Intent(ACTION_VIEW, ...)) can throw ActivityNotFoundException (notably for eid: if AusweisApp isn’t installed, but also for mailto: on minimal devices). Consider guarding with resolveActivity(packageManager) and/or catching the exception and surfacing a user-visible error via onErrorReceived instead of crashing.

Copilot uses AI. Check for mistakes.
}
Expand Down
Loading