Android's addJavascriptInterface lets JavaScript in a WebView call methods on a native object, which is powerful and risky. On Android below API 17 it exposed every public method, so attacker-controlled JavaScript could use reflection to reach Runtime.exec and run arbitrary code, the flaw tracked as CVE-2012-6636. From API 17, only methods annotated with @JavascriptInterface are exposed, which narrows the attack surface but does not remove it. Any method you expose is still callable, so loading untrusted or interceptable content into such a WebView remains dangerous.
Short answer
addJavascriptInterface bridges JavaScript to a native object, and its risk depends on your API level and what content the WebView loads. Per the Android WebView reference, apps targeting API 17 and above only expose methods marked @JavascriptInterface, which closed the original reflection-to-RCE exploit (CVE-2012-6636) that affected older versions. The remaining risk is that any exposed method is callable by whatever JavaScript runs, so a WebView that loads untrusted or interceptable content can still be abused. Test only your own app on an isolated device, minimize the exposed surface, load first-party HTTPS content, and prefer a modern message channel as a safer bridge, in line with OWASP MASVS guidance.
What addJavascriptInterface does
addJavascriptInterface takes a native object and a name and injects that object into the WebView's JavaScript context under the given global name, so page scripts can call its methods as if they were JavaScript functions. It is used to let web content trigger native behavior, such as reading a value from the app or invoking a native feature, which is why hybrid apps reach for it.
The power is also the problem. Once an object is exposed, any JavaScript running in that WebView can call the exposed methods, and the WebView does not distinguish between your own trusted page and any other script that ends up executing. The safety of the bridge therefore depends entirely on what content the WebView loads and how narrow the exposed surface is.
How the exploit works
Understood defensively so you can spot it in your own app, the classic exploit abused the fact that older Android exposed every public method of the injected object to JavaScript. That included inherited methods such as getClass(), so attacker-controlled script could call the object's getClass method and then use Java reflection to reach Runtime.getRuntime().exec(), executing arbitrary commands with the app's permissions.
The delivery was the other half. Because the attack only needs JavaScript to run in the WebView, loading remote content over cleartext HTTP let a network attacker inject the malicious script through a man-in-the-middle, and a hostile ad or iframe could do the same. This combination, an over-exposed interface plus untrusted content, is what turned a convenience API into remote code execution, tracked as CVE-2012-6636.
The API 17 boundary and @JavascriptInterface
Android 4.2, API level 17, changed the rule: for apps targeting API 17 or higher, only methods explicitly annotated with @JavascriptInterface are visible to JavaScript. Unannotated methods, including getClass(), are no longer reachable, which closes the reflection path used by the original exploit. This is why the annotation is now required to expose anything at all.
The target API level is the key limit. The protection applies when your app targets API 17 or above and runs on Android 4.2 or later, which covers essentially all current devices. If you were to target an API below 17, or run on a very old device, the old all-methods behavior applies and the classic exploit returns. In practice you should target a modern API and rely on the annotation, but treat it as narrowing the surface, not as making the bridge safe by itself.
Is it still a risk on modern Android?
Yes, in a narrower form. The reflection-to-RCE path is closed on modern Android, but every method you annotate with @JavascriptInterface is still callable by any JavaScript in the WebView. If one of those methods does something sensitive and the WebView can load untrusted or interceptable content, an attacker who gets script to run can still call it. The table below summarizes how exposure and risk change by version and content.
| Version or content | What JavaScript can reach | Risk level |
|---|---|---|
| Target below API 17 | All public methods, including via reflection | Critical, reflection to Runtime.exec |
| Target API 17 and above | Only @JavascriptInterface methods | Reduced, exposed methods still callable |
| WebView loads untrusted or remote content | Your exposed bridge methods | High if content can be intercepted |
| Trusted first-party HTTPS only | Your exposed bridge methods | Lower, keep the surface minimal |
The takeaway is that two things drive the real risk: your target API level, which decides whether reflection is possible, and the trustworthiness of the content, which decides whether hostile script can run at all. Control both, not just one.
How to test your own WebView responsibly
Test only your own app, on a device or emulator you control, in an isolated environment. Start by finding every addJavascriptInterface call and listing exactly which methods are annotated and what they do, since that is your real exposed surface. Confirm the WebView only loads first-party content over HTTPS and that mixed content is disabled.
For dynamic checks, load a local test page into your own WebView and try calling the exposed bridge from JavaScript to confirm only the intended methods are reachable and behave safely. Tools such as Frida can help you observe the bridge on your own build, and OWASP MASTG describes WebView and JavaScript-interface tests in detail. Keep all of this scoped to software you own, with the goal of shrinking the exposed surface rather than attacking anything external.
Remediation checklist
Remediation is about necessity, a minimal surface, and trusted content. The checklist below captures the fixes that matter most, from removing the interface to hardening what the WebView loads.
| Check | Action | Done? |
|---|---|---|
| Necessity | Remove addJavascriptInterface where it is not truly needed | [ ] |
| Minimal surface | Annotate only required methods, keep them few and harmless | [ ] |
| Content trust | Load first-party HTTPS only; disable mixed content | [ ] |
| WebView hardening | Turn off file access and universal access from file URLs | [ ] |
| Modern bridge | Prefer an allow-listed message listener over a raw interface | [ ] |
The single most effective step is to load only trusted first-party content over HTTPS into any WebView that has a JavaScript interface, with mixed content disabled so remote script cannot be injected. After that, keep the exposed methods as few and as harmless as possible, and remove the interface entirely wherever it is not truly needed.
Safer alternatives
Modern Android offers safer ways to bridge web and native than a broad JavaScript interface. The AndroidX WebViewCompat.addWebMessageListener lets you receive messages from specific, allow-listed origins over a structured channel, which gives you the communication you need without exposing arbitrary native methods to any script on the page.
Where you only need to pass data one way, evaluateJavascript and a postMessage-style channel are often enough and expose far less. Choosing one of these over addJavascriptInterface reduces the surface by design, so even if untrusted content somehow runs, there is little for it to call. Treat addJavascriptInterface as a last resort for cases these alternatives cannot cover.
Where this fits in a security scan
A JavaScript interface exposed to a WebView that loads remote content is a classic finding a security review should surface, alongside cleartext traffic, weak WebView settings, and stored secrets. It is easy to miss by hand, because the risky combination is spread across an addJavascriptInterface call, the WebView's settings, and the URLs it loads.
A scanner like PTKD.com analyzes your app build and reports findings ordered by severity and mapped to OWASP MASVS, which helps you see an exposed interface and weak WebView configuration in context rather than one line at a time. To be clear about the boundary: a scanner points to where the risk is, and you still remove or narrow the interface, lock down what the WebView loads, and choose a safer bridge in code.
What to take away
- addJavascriptInterface bridges JavaScript to a native object, and any exposed method is callable by whatever script runs in the WebView.
- Below API 17 it exposed all public methods, enabling reflection to Runtime.exec and remote code execution, tracked as CVE-2012-6636.
- From API 17, only @JavascriptInterface methods are exposed, which narrows but does not remove the risk.
- The real risk is driven by your target API level and whether the WebView can load untrusted or interceptable content.
- Load only first-party HTTPS content, minimize the exposed surface, prefer a message listener, and scan with PTKD.com.




