Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMissing authorization in WebView
DescriptionMissing authorization in WebView
ComponentWebView
Bug ClassLogic Error
Tracker507219126
Fix commite84aaf8b1e01 (chromium/src) +143/-3
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
if
android_webview/browser/aw_content_browser_client.cc
modified

Files Changed

  • android_webview/browser/BUILD.gn
  • android_webview/browser/DEPS
  • android_webview/browser/aw_content_browser_client.cc
  • android_webview/browser/aw_content_browser_client.h
  • android_webview/common/aw_features.cc
  • android_webview/common/aw_features.h
  • android_webview/javatests/DEPS
  • android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java
From e84aaf8b1e016ff23ddc3e4d6e9e5d5e7ec6f35f Mon Sep 17 00:00:00 2001
From: Nate Fischer <[email protected]>
Date: Tue, 04 Aug 2026 23:18:51 -0700
Subject: [PATCH] Block WebAuthn requests on pages with SSL errors

AwContentBrowserClient inherits
ContentBrowserClient::IsSecurityLevelAcceptableForWebAuthn which
unconditionally returns true, allowing WebAuthn requests to proceed
without considering TLS errors.

This CL overrides IsSecurityLevelAcceptableForWebAuthn in
AwContentBrowserClient to check the security level similar to what
Chrome browser does. This adds an end-to-end test verifying WebAuthn is
blocked on sites with SSL errors.

TAG=agy
CONV=c1aad737-b624-4e3e-8c12-a5dd34c64316

Fixed: 507219126
Test: run_webview_instrumentation_test_apk -f WebAuthnTest.*
Change-Id: I977fe7ec62450f2ab6ae93458a2bd6d62213315e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8178688
Auto-Submit: Nate Fischer <[email protected]>
Reviewed-by: Rupert Wiser <[email protected]>
Commit-Queue: Rupert Wiser <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1673924}
---

diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn
index 09c77123..cec21723b 100644
--- a/android_webview/browser/BUILD.gn
+++ b/android_webview/browser/BUILD.gn
@@ -297,6 +297,7 @@
     "//components/minidump_uploader",
     "//components/navigation_interception",
     "//components/network_hints/browser",
+    "//components/network_session_configurator/common",
     "//components/optimization_guide/core:bloomfilter",
     "//components/origin_matcher",
     "//components/origin_trials:browser",
@@ -332,6 +333,8 @@
     "//components/sampling_profiler:profile_params",
     "//components/security_interstitials/content:security_interstitial_page",
     "//components/security_interstitials/core",
+    "//components/security_state/content",
+    "//components/security_state/core",
     "//components/sensitive_content",
     "//components/services/heap_profiling/public/cpp",
     "//components/spellcheck:buildflags",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 8f171c20..1a571c2 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -52,6 +52,8 @@
   "+components/safe_browsing/core/browser",
   "+components/safe_browsing/core/common",
   "+components/security_interstitials",
+  "+components/security_state/content",
+  "+components/security_state/core",
   "+components/sensitive_content",
   "+components/services/heap_profiling",
   "+components/spellcheck/browser",
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 13dabf1a..eadf3d5 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -81,6 +81,7 @@
 #include "components/embedder_support/user_agent_utils.h"
 #include "components/heap_profiling/in_process/heap_profiler_controller.h"
 #include "components/navigation_interception/intercept_navigation_delegate.h"
+#include "components/network_session_configurator/common/network_switches.h"
 #include "components/page_load_metrics/browser/metrics_navigation_throttle.h"
 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
 #include "components/policy/content/policy_blocklist_navigation_throttle.h"
@@ -93,6 +94,8 @@
 #include "components/safe_browsing/core/common/features.h"
 #include "components/safe_browsing/core/common/hashprefix_realtime/hash_realtime_utils.h"
 #include "components/sampling_profiler/process_type.h"
+#include "components/security_state/content/content_utils.h"
+#include "components/security_state/core/security_state.h"
 #include "components/url_matcher/url_matcher.h"
 #include "components/url_matcher/url_util.h"
 #include "components/user_prefs/user_prefs.h"
@@ -125,6 +128,7 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "net/android/network_library.h"
 #include "net/base/features.h"
+#include "net/base/url_util.h"
 #include "net/cookies/cookie_setting_override.h"
 #include "net/cookies/site_for_cookies.h"
 #include "net/http/http_util.h"
@@ -583,6 +587,32 @@
   }
 }
 
+bool AwContentBrowserClient::IsSecurityLevelAcceptableForWebAuthn(
+    content::RenderFrameHost* rfh,
+    const url::Origin& caller_origin) {
+  if (!base::FeatureList::IsEnabled(
+          android_webview::features::kWebViewWebAuthnRequiresSecureOrigin)) {
+    return true;
+  }
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(rfh);
+  if (!web_contents) {
+    return false;
+  }
+  if (net::IsLocalhost(caller_origin.GetURL())) {
+    return true;
+  }
+  auto state = security_state::GetVisibleSecurityState(web_contents);
+  if (!state) {
+    return false;
+  }
+  security_state::SecurityLevel security_level =
+      security_state::GetSecurityLevel(*state);
+  return security_level == security_state::SecurityLevel::SECURE ||
+         base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kIgnoreCertificateErrors);
+}
+
 base::OnceClosure AwContentBrowserClient::SelectClientCertificate(
     content::BrowserContext* browser_context,
     int process_id,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index f18b542f..a2adea2 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -108,6 +108,9 @@
       bool strict_enforcement,
       base::OnceCallback<void(content::CertificateRequestResultType)> callback)
       override;
+  bool IsSecurityLevelAcceptableForWebAuthn(
+      content::RenderFrameHost* rfh,
+      const url::Origin& caller_origin) override;
   base::OnceClosure SelectClientCertificate(
       content::BrowserContext* browser_context,
       int process_id,
diff --git a/android_webview/common/aw_features.cc b/android_webview/common/aw_features.cc
index cdcdcd6..0433b98 100644
--- a/android_webview/common/aw_features.cc
+++ b/android_webview/common/aw_features.cc
@@ -406,6 +406,10 @@
 // browser process startup in WebView.
 BASE_FEATURE(kWebViewWarmupNetworkService, base::FEATURE_DISABLED_BY_DEFAULT);
 
+// When enabled, WebAuthn requests are blocked on pages with TLS/SSL errors.
+BASE_FEATURE(kWebViewWebAuthnRequiresSecureOrigin,
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Kill switch for reporting web performance metrics.
 BASE_FEATURE(kWebViewWebPerformanceMetricsReporting,
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/android_webview/common/aw_features.h b/android_webview/common/aw_features.h
index bf614a6..836493d 100644
--- a/android_webview/common/aw_features.h
+++ b/android_webview/common/aw_features.h
@@ -99,6 +99,7 @@
 BASE_DECLARE_FEATURE(kWebViewUseWVLESForLayeredStudy);
 BASE_DECLARE_FEATURE(kWebViewVizDirectCompositorThreadIpcFrameSinkManager);
 BASE_DECLARE_FEATURE(kWebViewWarmupNetworkService);
+BASE_DECLARE_FEATURE(kWebViewWebAuthnRequiresSecureOrigin);
 BASE_DECLARE_FEATURE(kWebViewWebPerformanceMetricsReporting);
 // Don't add new features to the end! Insert them in alphabetical order to
 // reduce conflicts.
diff --git a/android_webview/javatests/DEPS b/android_webview/javatests/DEPS
index 15d6e6f..43dac3b 100644
--- a/android_webview/javatests/DEPS
+++ b/android_webview/javatests/DEPS
@@ -9,6 +9,7 @@
   "+components/policy/android/javatests",
   "+components/safe_browsing/android/java",
   "+components/variations/android/java",
+  "+components/webauthn/android/java/src/org/chromium/components/webauthn",
 
   "-content/public/android/java",
   "+content/public/android/java/src/org/chromium/content_public",
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java
index 3477bc0..2448307 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java
@@ -4,8 +4,17 @@
 
 package org.chromium.android_webview.test;
 
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.ResultReceiver;
+
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -22,8 +31,14 @@
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java
index 3477bc0..2448307 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebAuthnTest.java
@@ -4,8 +4,17 @@
 
 package org.chromium.android_webview.test;
 
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.ResultReceiver;
+
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -22,8 +31,14 @@
 import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.HistogramWatcher;
+import org.chromium.blink.mojom.PublicKeyCredentialRequestOptions;
+import org.chromium.components.webauthn.AuthenticationContextProvider;
+import org.chromium.components.webauthn.Fido2ApiCallHelper;
 import org.chromium.components.webauthn.WebauthnMode;
+import org.chromium.components.webauthn.cred_man.CredManSupportProvider;
 import org.chromium.content_public.common.ContentSwitches;
+import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.net.test.ServerCertificate;
 import org.chromium.net.test.util.TestWebServer;
 import org.chromium.url.GURL;
 
@@ -32,6 +47,23 @@
 @CommandLineFlags.Add({ContentSwitches.HOST_RESOLVER_RULES + "=MAP * 127.0.0.1"})
 @Batch(Batch.PER_CLASS)
 public class WebAuthnTest {
+    private static class TestFido2ApiCallHelper extends Fido2ApiCallHelper {
+        public boolean mGetAssertionCalled;
+
+        @Override
+        public void invokeFido2GetAssertion(
+                AuthenticationContextProvider authenticationContextProvider,
+                PublicKeyCredentialRequestOptions options,
+                Uri uri,
+                byte[] clientDataHash,
+                ResultReceiver resultReceiver,
+                OnSuccessListener<PendingIntent> successCallback,
+                OnFailureListener failureCallback) {
+            mGetAssertionCalled = true;
+            failureCallback.onFailure(new Exception("MOCK_FIDO2_API_INVOKED"));
+        }
+    }
+
     @Rule public AwActivityTestRule mActivityTestRule = new AwActivityTestRule();
 
     private TestAwContentsClient mContentsClient;
@@ -158,6 +190,69 @@
         histogramWatcher.assertExpected();
     }
 
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testWebAuthnBlockedOnSslError() throws Throwable {
+        CredManSupportProvider.setupForTesting(Build.VERSION_CODES.TIRAMISU, false);
+        TestFido2ApiCallHelper testHelper = new TestFido2ApiCallHelper();
+        Fido2ApiCallHelper.overrideInstanceForTesting(testHelper);
+
+        EmbeddedTestServer testServer =
+                EmbeddedTestServer.createAndStartHTTPSServer(
+                        InstrumentationRegistry.getInstrumentation().getContext(),
+                        ServerCertificate.CERT_MISMATCHED_NAME);
+        try {
+            mAwSettings.setJavaScriptEnabled(true);
+            mAwSettings.setWebauthnSupport(WebauthnMode.APP);
+            mContentsClient.setAllowSslError(true);
+
+            final String pageUrl =
+                    testServer.getURLWithHostName(
+                            "a.test", "/android_webview/test/data/hello_world.html");
+            mActivityTestRule.loadUrlSync(
+                    mAwContents, mContentsClient.getOnPageFinishedHelper(), pageUrl);
+
+            mActivityTestRule.executeJavaScriptAndWaitForResult(
+                    mAwContents,
+                    mContentsClient,
+                    """
+                    window.webauthnResult = 'PENDING';
+                    navigator.credentials.get({
+                      publicKey: {
+                        challenge: new Uint8Array([1, 2, 3, 4]),
+                        timeout: 500,
+                        rpId: 'a.test'
+                      }
+                    }).then(
+                      () => { window.webauthnResult = 'SUCCESS'; },
+                      (e) => { window.webauthnResult = e.name + ': ' + e.message; }
+                    );
+                    """);
+
+            AwActivityTestRule.pollInstrumentationThread(
+                    () -> {
+                        String val =
+                                mActivityTestRule.executeJavaScriptAndWaitForResult(
+                                        mAwContents, mContentsClient, "window.webauthnResult");
+                        return !"\"PENDING\"".equals(val) && !"null".equals(val);
+                    });
+
+            String result =
+                    mActivityTestRule.executeJavaScriptAndWaitForResult(
+                            mAwContents, mContentsClient, "window.webauthnResult");
+
+            Assert.assertFalse(
+                    "FIDO2 API should not be invoked for pages with SSL errors",
+                    testHelper.mGetAssertionCalled);
+            Assert.assertTrue(
+                    "WebAuthn should be blocked due to SSL error, but got: " + result,
+                    result.contains("NotAllowedError") && result.contains("certificate errors"));
+        } finally {
+            testServer.stopAndDestroyServer();
+        }
+    }
+
     private static boolean isSecureDomain(GURL url) {
         if ("https".equals(url.getScheme())) {
             return true;
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 1d748689..69b320f 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -276,9 +276,8 @@
 android_library("webview_compose_javatests") {
   testonly = true
   enable_compose = true
-  sources = [
-    "../javatests/src/org/chromium/android_webview/test/AwComposeTest.kt",
-  ]
+  sources =
+      [ "../javatests/src/org/chromium/android_webview/test/AwComposeTest.kt" ]
   deps = [
     ":base_webview_instrumentation_java",
     ":base_webview_instrumentation_test_java",
@@ -309,6 +308,7 @@
 
   deps = [
     ":webview_compose_javatests",
+    "$google_play_services_package:google_play_services_tasks_java",
     "//android_webview:common_aidl_java",
     "//android_webview:common_origin_trials_java",
     "//android_webview:common_variations_java",
@@ -384,6 +384,7 @@
     "//third_party/androidx_javascriptengine:javascriptengine_java",
     "//third_party/blink/public:blink_headers_java",
     "//third_party/blink/public/common:common_java",
+    "//third_party/blink/public/mojom:authenticator_mojo_bindings_java",
     "//third_party/blink/public/mojom:mojom_platform_java",
     "//third_party/blink/public/mojom:web_feature_mojo_bindings_java",
     "//third_party/google-truth:google_truth_java",
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.