Universal XSS in Android WebView (CVE-2020-6506)

September 10, 2020 about Vulnerabilities, Android, UXSS, CVE-2020-6506

Summary

CVE-2020-6506 (crbug.com/1083819) is a universal cross-site scripting (UXSS) vulnerability in Android WebView which allows cross-origin iframes to execute arbitrary JavaScript in the top-level document. This vulnerability affects vendors which use Android WebView with a default configuration setting, and whose apps run on systems with Android WebView version prior to 83.0.4103.106 Stable. The vulnerability appears to have been introduced in or around 76.0.3809.21 Beta / 76.0.3809.89 Stable.

I discovered this vulnerability while pentesting over a dozen Android web browsers, and determined the cause was Android WebView behavior. A large amount of tested browsers were vulnerable, either due to their own code or dependencies. These dependencies are frameworks which are widely used in many applications.

In a vast majority of cases, impacts are typical for a UXSS. However, in very limited cases, this UXSS could be used to access privileged application-exposed APIs, and in very rare cases, use those APIs perform scoped Remote Code Execution (RCE). No widely-used production app has been identified as vulnerable to scoped RCE via this UXSS, but I have verified this as technically possible.

This article uses present tense to describe the vulnerability; however, users with a patched version of Android WebView are no longer vulnerable.

Android WebView at a glance

Android WebView is a system component which allows Android apps to display web pages. Apps typically use Android WebView directly or via frameworks/libraries.

The version of Android WebView used by an app is tied to the version of Android WebView installed in the system, and is updatable via the Google Play Store like any other app and many other system components. Modern versions of Android WebView are not tied to an Android operating system version or an application build.

With few exceptions, most third-party browsers on Android use WebViews to render pages, making it an interesting attack surface. A vulnerability in WebView could affect all these third-party browsers, in addition to many other apps.

While Android WebView uses Chromium under the hood, some vulnerabilities prevented by Chrome for Android may still work in WebViews under certain configurations. CVE-2020-6506 is an example of such a vulnerability.

CVE-2020-6506 vulnerability details

An Android WebView instance with WebSettings.setSupportMultipleWindows() kept at default or set to false allows an iframe on a different origin bypass same-origin policies and execute arbitrary JavaScript in the top document.

When multiple windows support is false, WebView handles new windows with javascript: URLs in the same way as new windows with https:// URLs (sidenote 1), which is to navigate the top document to the provided URL. This leads to JavaScript being executed in the top document context.

To perform the attack, an iframe can call window.open() with a javascript: URL. Other methods of opening a new window, such as a link with target="_blank" and href="javascript:...", can also be used to perform the attack.

Performing the attack requires a single user interaction (a tap/click or a keypress), because WebView requires an interaction to open a new window. The malicious iframe does not need to be visible, and can obtain the keypress interaction while a user attempts to type in the top-level document (no direct iframe interaction required). See PoC videos below.

In rare configurations, no user interaction is required (drive-by attack). The top-level page must be loaded using the file:// scheme and the WebView must set both WebSettings.setJavaScriptCanOpenWindowsAutomatically() and WebSettings.setAllowUniversalAccessFromFileURLs() to true.

The patched version of Android WebView (83.0.4103.106) was released on Monday, June 15th, 2020. Users must be running at least this version of WebView to be fully protected. Apps can and should implement mitigations for users running unpatched versions of WebView, since users are not guaranteed to be running a patched WebView version.

Sidenote 1: Allowing any iframe, including cross-origin iframes, to navigate top-level windows to another https:// URL is intentionally allowed in WebViews for legacy/compatibility reasons. Even after CVE-2020-6506 is fixed, WebViews with this configuration still allow unwanted navigations which could pose a security risk if the page origin is not safely displayed to the user. The crbug report and subsequent discussion has more info. I may write an article about this soon.

Impacts and attack launch surfaces

Confirmed impacts and attack launch surfaces:

A malicious iframe on any page within the vulnerable WebView can perform a UXSS attack on the top-level document with minimal user interaction. The interaction can be unintentional if chained with another bug to perform keyboard focus theft.

In rare configurations, no user interaction is required (drive-by attack). The top-level page must be loaded using the file:// scheme and the WebView must set both WebSettings.setJavaScriptCanOpenWindowsAutomatically() and WebSettings.setAllowUniversalAccessFromFileURLs() to true. See Apache Cordova details.

Any iframe, visible or hidden, can perform the attack as long as it can obtain a single user interaction. Hidden iframes can only perform the attack by stealing keyboard input focus, using behavior described in crbug.com/622714. Visible iframes can perform the attack by either receiving a tap/click or keypress. Visible iframes can also steal keyboard input focus.

The ability to launch attacks from hidden iframes significantly increases the number of potential website targets due to their more widespread usage and ability to steal user activations with minimal cooperation (if you can call it that) from the user.

In certain apps, this UXSS can be used to access privileged APIs, which can lead to other vulnerabilities. Some APIs may allow Remote Code Execution (RCE) with the privileges of the application. This is typical in some frameworks, although other security controls and good developer practices means it's unusual to find iframes capable of performing this attack within these privileged pages or WebViews.

For click user activation scenarios, in addition to display/video ads, other common scenarios where visible 3P iframes are likely to obtain a click user activation by mobile users include: video players, in-page chat, comment forms/display, share buttons, documents, and contact/survey forms. If the 3P is unscrupulous or has a stored XSS vuln within the iframe, an attack seems realistic, affecting users of vulnerable browsers/WebViews who browse sites with these 3P iframes. Any of these can also combine the keyboard method for increased effectiveness.

I've verified attacks can be launched from any iframe regardless of nesting depth. This means if the malicious iframe is nested within 5 other iframes, window.open()/target="_blank" will still execute code at top level if the malicious iframe five levels deep obtains user activation. The keyboard focus theft attack also works at any nesting depth. Attack launch is possible even in an attacker's worst-case scenario where each iframe is on a different origin. e.g. top level is example.com, iframes are nested in exampleiframe1.com, exampleiframe2.com, exampleiframe3.com, etc.

Theoretical chained impacts and attack launch surfaces:

The items below are theoretical impacts, possible only if an appropriate vulnerability is found and chained. These may have existed in the past, and perhaps will exist in the future. But as far as I know, they did not exist recently at the same time as CVE-2020-6506.

If a user interaction requirement bypass is found, in theory it could be chained to make CVE-2020-6506 exploitable in drive-by attacks. (For example, something better than the keyboard interaction method to minimize interactivity requirements.)

If an iframe sandboxing bypass is found, in theory it could be chained to make CVE-2020-6506 exploitable from sandboxed iframes. crbug.com/845983 is an example of a vulnerability which would have helped to bypass iframe sandboxing.

How to identify vulnerable apps

If an app renders pages using WebViews, and handles "new window" navigations in the same window/tab (meaning multiple window support is set to false), it's probably vulnerable. Surprisingly, many apps which implement multiple tabs functionality are affected, because they often only allow new tabs to be opened via their UI (not by pages within the WebView), therefore they keep the Android WebView's multiple windows support setting at false.

At its simplest, an app is vulnerable if they create a WebView like this:

class VulnerableActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...other setup code...
        
        // Get WebView from layout
        val myWebView: WebView = findViewById(R.id.webview)
        // Enable JavaScript (only configuration required)
        myWebView.settings.javaScriptEnabled = true
        // Load parent page
        myWebView.loadUrl("https://PARENT_ORIGIN/parent.html")
    }
}

Proof of concepts

Test an app by navigating its WebViews to these proof of concept (PoC) URLs:

With the PoCs above, the expected behavior is to have the attacker's JavaScript not execute at all or execute in an attacker origin. If vulnerable, the observed behavior is an element added to the top-level document (target). Depending on the WebView configuration, vulnerable behavior may also manifest as an alert() dialog with the target origin information. (See pitfalls below.)

Pitfalls when testing

Depending on their configuration, WebViews may not show alert() dialog boxes. Therefore, using a payload such as javascript:alert(document.domain) is not recommended as it may yield a false-negative. Instead, use a payload which first writes to the top-level document and then tries an alert(), such as javascript:var elem = document.createElement("p"); elem.innerHTML = "<b>Executed JS in parent origin: "+window.location.origin+"</b>"; document.body.append(elem); alert(document.domain).

Difficulties with repro?

The vulnerability appears to start reproducing in or around Android WebView version 76.0.3809.21 Beta / 76.0.3809.89 Stable. If the system is running Android WebView 75 or prior, it won't repro. The vulnerability was fixed in 83.0.4103.106 Stable, so newer versions also won't repro.

Many thanks to Mateusz Bąk for helping to identify the earliest-reproducible version.

Potential mitigations

In an ideal world, users update their system components and apps on a regular basis. In the real world, apps may be vulnerable due to users not updating their WebView component for a variety of reasons.

For these users who remain vulnerable, apps and websites can implement mitigations to prevent attacks. Mitigation makes apps safer for users even if they have a vulnerable WebView version, and protects websites while being browsed in vulnerable apps.

Android applications and frameworks

For Android applications, mitigation is simple in most cases. In other cases, there's a bit more work, but overall feasible.

For frameworks, mitigation tends to be more complex due to the variety of supported use cases.

For Android applications vulnerable due to a dependency (e.g. a framework), updating the dependency version should be sufficient in most cases. Some dependencies' mitigation strategies may introduce breaking changes in certain use cases. Advisories should be reviewed for breaking changes.

Vendors generally have two choices to mitigate for unpatched WebView users:

  1. Enable multiwindow support. If needed, implementation options exist to mimic single-window behavior and minimize breaking changes. Does not require multi-tab UI. Suitable for browsers and frameworks.
  2. Keep multiwindow support disabled, and strictly limit WebView rendering to trusted content only. Suitable for non-browser apps, and for frameworks when used in non-browser apps.

To keep this article from becoming extremely long, I've omitted the detailed mitigation options. If you need the details to mitigate CVE-2020-6506 in an app, send me an email.

Adjacent phishing mitigation: If the current page URL is not guaranteed to be shown to the user, origin allowlists are recommended to mitigate phishing risks. This is an adjacent vulnerability, but it's a good opportunity to mitigate it because URL filtering is likely to be implemented as part of the UXSS mitigation.

Websites

iframe sandboxing works as expected to prevent the attack. However, there are common configurations which still unexpectedly allow JavaScript from the iframe to execute in the parent document. For example, using sandbox="allow-popups allow-top-navigation allow-scripts" allows the attack to be performed by the iframe. Similar sandbox configurations may also allow the attack, but I have not tested them.

iframe sandboxing provides other benefits, including protecting from other types of existing and future attacks. I recommend using sandboxed iframes for any iframes containing user content or third-party content to prevent a website from being vulnerable.

Ensure any third-party scripts loaded on the website also use appropriately sandboxed iframes.

Android Users

Update Android WebView version 83.0.4103.106 or higher using the Google Play Store. Users should update Android WebView automatically or on a regular basis to receive other security fixes and improvements.

Affected vendors

There's a long list of identified affected vendors, and a vast majority of them received a security report within the past few months. The response from many vendors has been to mitigate this vulnerability for users who may be using unpatched WebView versions. However, some vendors are still pending mitigations, and other vendors have not responded with any substantial details on their intended actions.

More vendors will be added to this list. I'm waiting for disclosure approvals or disclosure deadlines to arrive.

Mitigated

Pending mitigations

  • Apache Cordova (framework), drive-by attack
    • Advisory issued. No built-in mitigation available yet.
    • The main app WebView and the InAppBrowser WebView are both vulnerable. Using InAppBrowser to render pages does not mitigate.
    • No user interaction required to exploit in the main app WebView due to two reasons:
      1. Cordova sets both WebSettings.setJavaScriptCanOpenWindowsAutomatically() and WebSettings.setAllowUniversalAccessFromFileURLs() to true.
      2. If the top-level document is loaded using file:// scheme, Android WebView does not require user interaction inside a cross-origin iframe to open a new window. (In comparison, Android WebView requires user interaction if the top-level document is loaded using https:// even if automatic window opening is enabled.)
  • Capacitor by Ionic (framework)

Will not mitigate

  • Trust Wallet (browser)

There are several vendors pending mitigations, many due to reasons out of their control (dependencies introduced vulnerability). They will be added under "Mitigated" once they've mitigated and approved disclosure, or if they go past their individual disclosure deadlines without mitigation.

For apps affected via a dependency, the identified dependency vendors have received security reports and are at various stages of response. The vulnerable dependencies are included in the vendor list above.

Identified apps vulnerable due to dependencies will only be listed after they've received a security report and have approved disclosure or go past their individual disclosure deadlines. The identified apps have received a security report now that dependencies have issued security advisories.

Videos

PoC 1: Tap interaction

PoC 2: Keypress interaction

Thanks for reading. Don't miss any new research: Get new articles via email.

Share on Mastodon, Twitter, Facebook, LinkedIn, permalink.

Did this article help you discover a vulnerability? I want to hear about it: Send me an email.

Alesandro Ortiz is a Software Engineer and Security Researcher focused on improving the web.

All articles

Home page