FlawOpen

flawopen.com/Android WebView security/addJavascriptInterface

Android addJavascriptInterface: security risks and safe use

Reference page
Short answer

Treat a WebView with addJavascriptInterface as a privileged boundary. Android injects the object into every frame and cannot tell your app which frame called it. If attacker-controlled JavaScript reaches any frame, it may invoke exposed bridge methods with the app's permissions. Keep bridged WebViews limited to app-controlled content, and load untrusted pages in a separate WebView without the bridge.

Why the bridge changes the XSS impact

A bridge gives JavaScript callable entry points into the host app. Android exposes the object to every frame, including iframes, and provides no calling-frame origin check for addJavascriptInterface. A script injected into a page or frame can therefore reach annotated bridge methods; what it can do next is bounded by those methods and the app's own authorization checks. On apps targeting API 16 or earlier, Android documents a more severe legacy behavior: all public methods may be exposed. API 17+ requires @JavascriptInterface, but that annotation does not make untrusted content safe.

Keep the bridge away from untrusted pages

RISKY — bridge and untrusted navigation share a WebView
webView.addJavascriptInterface(
  NativeBridge(), "Android"
)
webView.loadUrl(untrustedUrl)
SAFER — separate trusted and untrusted content
// This WebView is reserved for packaged, app-controlled UI.
trustedWebView.settings.javaScriptEnabled = true
trustedWebView.addJavascriptInterface(
  NativeBridge(), "Android"
)
trustedWebView.loadUrl("file:///android_asset/index.html")

// A different WebView handles remote or user-controlled pages.
untrustedWebView.removeJavascriptInterface("Android")
untrustedWebView.settings.javaScriptEnabled = false
// Validate HTTPS and an explicit host allowlist.
untrustedWebView.loadUrl(validatedHttpsUrl)

The strongest boundary is architectural: never navigate a bridge-enabled WebView to a remote, user-generated, or otherwise attacker-influenced page. If navigation to untrusted content is unavoidable, remove the interface before loading it and use a separate WebView with JavaScript disabled unless required. Android notes that the injected object is available to all frames and that removal takes effect after the next page load. HTTPS protects transport; it does not make a host or its content trusted. Validate both URL scheme and host, and open out-of-scope links in the system browser. Keep bridge methods narrow, validate every argument, and enforce user authorization in native code rather than trusting the calling page.

Android WebView bridge security FAQ

Does API 17+ make addJavascriptInterface safe?

No. API 17+ limits exposure to public methods annotated with @JavascriptInterface; it does not add a caller-frame origin check or make attacker-controlled content trustworthy. Keep the bridge on a WebView that only loads content your app controls.

References

See also Cross-Site Scripting (XSS, CWE-79): How It Works and How to Prevent It in Every Language — flawopen.com Angular XSS Protection: Safe Defaults and Bypass APIs Content-Type Sniffing XSS: MIME Types and nosniff CSP vs. Output Escaping: Do You Need Both? Is React's dangerouslySetInnerHTML Safe? Is DOMPurify Enough for Safe innerHTML? Is Markdown Rendering Safe from XSS?