Skip to content

[Bug]: Android does not inject the Capacitor bridge after navigating to an allowNavigation URL #8661

Open

Description

@gilperon

Capacitor Version

💊 Capacitor Doctor 💊

Latest Dependencies:

@capacitor/cli: 8.5.3
@capacitor/core: 8.5.3
@capacitor/android: 8.5.3
@capacitor/ios: 8.5.3

Installed Dependencies:

@capacitor/cli: 8.5.3
@capacitor/core: 8.5.3
@capacitor/android: 8.5.3
@capacitor/ios: 8.5.3

[success] iOS looking great! 👌
[success] Android looking great! 👌

Other API Details

Platforms Affected

  • iOS
  • Android
  • Web

Current Behavior

On Android, the app starts on the local origin (https://localhost) and then navigates with window.location to a remote URL listed in server.allowNavigation (for example https://client.example.com).

allowNavigation keeps the navigation inside the WebView, but native plugins stop working on the remote page. Calls fail with UNIMPLEMENTED / "plugin is not implemented on android". window.Capacitor.PluginHeaders is empty on the new origin.

Cause: Bridge.loadWebView() registers the bridge with WebViewCompat.addDocumentStartJavaScript only for the appUrl origin:

WebViewCompat.addDocumentStartJavaScript(webView, injector.getScriptString(), Collections.singleton(allowedOrigin));

allowedOrigin is derived from appUrl (https://localhost). The allowNavigation origins are already collected in allowedOriginRules, but that set is not passed to addDocumentStartJavaScript.

iOS does not have this problem. WKUserScript is injected at document start on every main-frame load, with no origin filter, so plugins keep working after the same redirect.

This is still the case in the 8.5.3 tag, and also in 9.0.0-alpha.8:
https://github.com/ionic-team/capacitor/blob/8.5.3/android/capacitor/src/main/java/com/getcapacitor/Bridge.java

Expected Behavior

After navigating to a URL allowed by server.allowNavigation, Android should keep the native bridge, same as iOS.

addDocumentStartJavaScript should receive allowedOriginRules (local origin, server.url when set, and allowNavigation origins), not only the appUrl origin. Plugins should keep working on the remote page without an app-level patch of Bridge.java.

Project Reproduction

https://github.com/Dylancyclone/capacitor-android-redirect

Additional Information

Same bug as #7454, still open. The reproduction repo linked above is the one from that issue. The one-line fix is already in #8429 (rebased from #7571) and has had no maintainer review. #7571 was closed for backlog rebase, not because the change was rejected.

Please land #8429, or apply the same change on main:

  •    WebViewCompat.addDocumentStartJavaScript(webView, injector.getScriptString(), Collections.singleton(allowedOrigin));
    
  •    WebViewCompat.addDocumentStartJavaScript(webView, injector.getScriptString(), allowedOriginRules);
    

Reproduced on 8.5.3. The same line is still present in 9.0.0-alpha.8. Apps currently have to patch @capacitor/android themselves to get iOS parity.

Activity

  1. added theissue type on Oct 15, 2026
  2. eric-horodyski commented on Oct 21, 2026

    @eric-horodyski
    Member

    Hi @gilperon, thanks for the writeup — it kicked off a useful discussion on our side.

    Letting sites outside the app origin reach window.Capacitor has never been intentional...it's a side effect of how the script is injected with iOS. After talking it through, we agree allowNavigation origins should get bridge access on both platforms.

    The timing is tough — Capacitor 9's scope is frozen so we can hit GA — and the change is also larger than the linked PR. The short version:

    • Android is stricter about the shape of origins than our allowNavigation config is, so the proposed fix quietly does nothing for a lot of real configurations.
    • Expanding bridge access without also tightening how we validate origins on the native side would lean on allowNavigation as the only line of defense — the same posture that GHSA-rvm3-566m-v7fv exploited. We want to avoid repeating that.

    We'll be looking to pick this up for Capacitor 10, since it counts as a breaking change either way. Thanks to you and @caffeinated10xprogrammer for pushing on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions