{"id":"CVE-2026-103922","aliases":["GHSA-rvm3-566m-v7fv"],"url":"https://o3.security/vulnerability/CVE-2026-103922","summary":"Capacitor Android and iOS: remote content can be loaded at the app origin via the internal HTTP proxy path","details":"### Impact\n\nCapacitor's WebView navigation guard validated only the **host and scheme** of a\ntarget URL, not its **path**. Because the internal HTTP proxy path\n(`/_capacitor_http_interceptor_`) is served at the application's own origin, a\nframe navigation to it was always treated as in-app navigation and allowed.\n\nLoading that path as a document caused the native layer to fetch an arbitrary,\ncaller-specified URL and return the response body to the WebView **at the app's\nown origin**. Script in that response then ran with full same-origin trust:\naccess to `localStorage`, cookies, and every native capability the application\nexposes through its registered Capacitor plugins.\n\nThe proxy handler was additionally served **regardless of whether the\n`CapacitorHttp` plugin was enabled**, so applications that never enabled\n`CapacitorHttp` were also affected.\n\nExploitation requires a victim to activate a link inside the application's\nWebView. Any Capacitor application that renders user-controlled or unsanitized\nlinks (chat messages, comments, rich-text content) is a viable delivery surface.\n\nBoth **Android and iOS** are affected.\n\n### Patches\n\nTwo changes on each platform:\n\n1. The navigation guard now blocks frame navigations whose path is the internal\n   proxy path.\n2. The proxy handler is served only when `CapacitorHttp` is enabled, and never\n   for a document (main frame) request.\n\nLegitimate `CapacitorHttp` usage is unaffected. `fetch` and `XMLHttpRequest` are\nsubresource requests and do not pass through the navigation guard.\n\nUpgrade to a patched version, then rebuild and redistribute your application.\n\n### Workarounds\n\nIf you cannot upgrade immediately, note first that **disabling `CapacitorHttp`\nis not sufficient** on affected versions, because the proxy path is served\nregardless of that setting.\n\nRegistered plugins are consulted before the navigation guard runs, so a small\nplugin can block the path. On Android, override `shouldOverrideLoad(Uri url)` and\nreturn `true` when `url.getPath()` starts with `/_capacitor_http_interceptor_`.\nOn iOS, implement `shouldOverrideLoad(_:)` and return `true` for the same path.\nReturning `true` cancels the navigation; return `null`/`nil` for all other URLs\nso normal navigation is unchanged.\n\nIndependently, sanitize user-controlled link targets before rendering them in the\nWebView.","published":"2026-10-01T17:27:05.758Z","modified":"2026-10-21T09:09:11.063106672Z","cvss":{"score":9.3,"severity":"CRITICAL","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"Maven","name":"com.capacitorjs:core","fixedVersion":"6.2.2"},{"ecosystem":"Maven","name":"com.capacitorjs:core","fixedVersion":"7.6.9"},{"ecosystem":"Maven","name":"com.capacitorjs:core","fixedVersion":"8.5.1"},{"ecosystem":"Maven","name":"com.capacitorjs:core","fixedVersion":"8.4.3"},{"ecosystem":"Maven","name":"com.capacitorjs:core","fixedVersion":null},{"ecosystem":"npm","name":"@capacitor/android","fixedVersion":"6.2.2"},{"ecosystem":"npm","name":"@capacitor/android","fixedVersion":"7.6.9"},{"ecosystem":"npm","name":"@capacitor/ios","fixedVersion":"6.2.2"},{"ecosystem":"npm","name":"@capacitor/ios","fixedVersion":"7.6.9"},{"ecosystem":"npm","name":"@capacitor/android","fixedVersion":"8.5.1"},{"ecosystem":"npm","name":"@capacitor/ios","fixedVersion":"8.5.1"},{"ecosystem":"npm","name":"@capacitor/android","fixedVersion":"8.4.3"},{"ecosystem":"npm","name":"@capacitor/ios","fixedVersion":"8.4.3"},{"ecosystem":"npm","name":"@capacitor/android","fixedVersion":null},{"ecosystem":"npm","name":"@capacitor/ios","fixedVersion":null},{"ecosystem":"SwiftURL","name":"github.com/ionic-team/capacitor-swift-pm","fixedVersion":"6.2.2"},{"ecosystem":"SwiftURL","name":"github.com/ionic-team/capacitor-swift-pm","fixedVersion":"7.6.9"},{"ecosystem":"SwiftURL","name":"github.com/ionic-team/capacitor-swift-pm","fixedVersion":"8.5.1"},{"ecosystem":"SwiftURL","name":"github.com/ionic-team/capacitor-swift-pm","fixedVersion":"8.4.3"},{"ecosystem":"SwiftURL","name":"github.com/ionic-team/capacitor-swift-pm","fixedVersion":null}],"fix":{"url":"https://github.com/ionic-team/capacitor/commit/430356a91e1419fc66862dc09835081aa501677e","label":"ionic-team/capacitor@430356a"},"references":[{"type":"WEB","url":"https://github.com/ionic-team/capacitor/releases/tag/8.5.1"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/103xxx/CVE-2026-103922.json"},{"type":"ADVISORY","url":"https://github.com/ionic-team/capacitor/security/advisories/GHSA-rvm3-566m-v7fv"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-103922"},{"type":"FIX","url":"https://github.com/ionic-team/capacitor/commit/430356a91e1419fc66862dc09835081aa501677e"},{"type":"FIX","url":"https://github.com/ionic-team/capacitor/commit/80b6c5e81d062e1e158914040f49e044d95b7ccb"},{"type":"FIX","url":"https://github.com/ionic-team/capacitor/commit/85ccc44151fdd5ae5e0d806d875766ef4b84ad5d"},{"type":"FIX","url":"https://github.com/ionic-team/capacitor/commit/af9a287fef45f0ac68ce640cb42fed2d06b0f1b4"},{"type":"FIX","url":"https://github.com/ionic-team/capacitor/commit/d5e3170ba0ff155fc542b7e6d16cff5201406540"},{"type":"FIX","url":"https://github.com/ionic-team/capacitor/commit/ee586ae680887ba99d066616f976db149542d922"},{"type":"WEB","url":"https://github.com/ionic-team/capacitor/commit/745b5f805bf77bc6463977cc7d718cd9de44ccbc"},{"type":"PACKAGE","url":"https://github.com/ionic-team/capacitor"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-21T09:09:11.063106672Z"}}