VNX-ANDROID-002 – Android WebView JavaScript Enabled
Overview
This rule reports Android WebViews (Java and Kotlin) that run script an attacker controls. Enabling JavaScript is not a finding on its own. The rule reports a loadUrl, loadData, loadDataWithBaseURL or postUrl call in a file that enables JavaScript when the URL or HTML comes from the launching Intent or a deep link (getIntent(), getStringExtra, getData, getQueryParameter, Fragment arguments), from external storage, or is a cleartext http:// address, either directly or through a variable assigned from such a source up to 15 lines above. It also reports addJavascriptInterface in a file with such a load, and setAllowUniversalAccessFromFileURLs(true) / setAllowFileAccessFromFileURLs(true). A URL checked between the read and the load (startsWith, host or scheme comparison, an allow-list or validator) is not reported, nor are https:// and file:///android_asset/ literals, http://localhost, comments and strings. Flows through other methods or files are not followed. These patterns are captured by CWE-79 (Improper Neutralization of Input During Web Page Generation).
Severity: High | CWE: CWE-79 – Improper Neutralization of Input During Web Page Generation (XSS)
Why This Matters
A WebView with JavaScript enabled and a registered JavascriptInterface gives any JavaScript running in that view direct access to the annotated Java methods. If the WebView ever loads attacker-controlled content — a redirected URL, an injected ad, a compromised CDN response — the attacker can call those Java methods and execute arbitrary native code on the device. On Android < 4.2, all public methods of any registered object were callable; from 4.2 onward only methods annotated with @JavascriptInterface are exposed, but the risk remains high.
Enabling universal file access (setAllowUniversalAccessFromFileURLs) allows a file:// URL to read any file the app has access to, enabling data theft across origins. Several banking apps have been attacked via this vector, where malicious deep-link payloads loaded a crafted file:// URL that exfiltrated the app’s database. CAPEC-86 documents this class of DOM-based XSS attack directly.
What Gets Flagged
// FLAGGED: a URL from the launching Intent loaded into a JavaScript-enabled WebView
webView.getSettings().setJavaScriptEnabled(true);
String target = getIntent().getStringExtra("url");
webView.loadUrl(target);
// FLAGGED: a statement file on external storage
webView.loadUrl("file://" + Environment.getExternalStorageDirectory() + "/statement.html");
// FLAGGED: file:// pages may read any origin
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
// FLAGGED: a deep-link parameter
settings.javaScriptEnabled = true
val page = intent.data?.getQueryParameter("page")
webView.loadUrl(page!!)
Not flagged: setJavaScriptEnabled(true) with only https:// or file:///android_asset/ loads, or an intent URL checked with Uri.parse(u).host == "help.example.com" before the load.
Remediation
Disable JavaScript unless you own every page the WebView loads. If you are building a hybrid app and must enable JavaScript, use a strict Content Security Policy delivered via HTTP headers or injected via
loadDataWithBaseURL.// SAFE: JavaScript disabled for content you do not control webView.getSettings().setJavaScriptEnabled(false);Remove
addJavascriptInterfacefrom production code. If a JS-to-native bridge is required, useWebMessageListener(API 23+) which scopes the bridge to specific allowed origins, or build the bridge using a safe messaging protocol verified inshouldOverrideUrlLoading.// SAFE: origin-scoped message listener instead of addJavascriptInterface webView.addWebMessageListener( "AndroidBridge", new HashSet<>(Arrays.asList("https://app.example.com")), (view, message, sourceOrigin, isMainFrame, replyProxy) -> { // handle message from trusted origin only } );Restrict file access. Call
setAllowFileAccess(false),setAllowFileAccessFromFileURLs(false), andsetAllowUniversalAccessFromFileURLs(false)explicitly. These settings default to disabled on modern API levels but should be set explicitly to prevent regressions.// SAFE: all file access disabled WebSettings settings = webView.getSettings(); settings.setAllowFileAccess(false); settings.setAllowFileAccessFromFileURLs(false); settings.setAllowUniversalAccessFromFileURLs(false);Validate URLs before loading. Override
shouldOverrideUrlLoadingandshouldInterceptRequestto enforce an allowlist of permitted origins. Rejectfile://,javascript:,data:, andintent://schemes unless explicitly required.Enable Safe Browsing. Call
WebView.startSafeBrowsing()to enable Google Safe Browsing malicious URL detection in the WebView.