Low watch CVSS 4.3 chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect reference resolution in WebView
DescriptionIncorrect reference resolution in WebView
ComponentWebView
Sub-componentWebview
Bug ClassLogic Error
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker517167020
Fix commit57f01d9195a8 (chromium/src) +30/-17
CWECWE-706
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-05-27 (per vendor advisory)
Fix landed2026-07-17 (public git)
Disclosed2026-08-25
Patch gap39 days — fix public in source before the advisory

Background

`WebAddressParser`
the Android WebView helper that parses a user/loaded address string into scheme, host, port, and path via an anchored regex, used to “fix up” URLs before navigation.
`MATCH_GROUP_PORT`
the regex capture group for the port that follows a ':'; the ':' itself is not returned in the captured text, so the group can be an empty string when a bare ':' matched.
`URISyntaxException`
the exception thrown to reject malformed addresses instead of silently emitting a fixed-up URL.

Root Cause Analysis

The parsing routine handled the port group with if (t != null && t.length() > 0), so when the PORT regex matched a bare ':' with zero following digits, the group was non-null but empty and the entire branch was skipped — silently dropping the ':' and keeping whatever had been captured as mHost. Because the ':' may actually have been a scheme delimiter (for an unrecognized scheme such as rtsp: in rtsp://www.example.com/media.mp4), dropping it changes how the remainder is interpreted and can yield a fixed-up URL whose host is not what the input denoted. The invariant that a parsed address either faithfully represents the input’s host or is rejected was violated, producing a wrong-host resolution (the advisory’s “incorrect reference resolution”).

The fix changes the guard to if (t != null) and, when t.length() == 0, throws URISyntaxException if mScheme.isEmpty() — i.e. it rejects a bare ':' whenever no scheme was recognized, rather than silently absorbing it; a legitimate empty port after a recognized scheme still passes. This tightens validation, and the test updates move several former “bad but accepted” inputs to the throwing set.

Key insight
Treating an empty port group (a bare ':' with no digits) as “nothing to do” silently dropped a colon that could be a scheme delimiter, letting the parser emit a URL with a mis-attributed host; the fix rejects that ambiguous ':' with URISyntaxException when no scheme was recognized.

Attack Path

  1. Craft an ambiguous address Supply WebView an address containing a ':' not followed by port digits and using an unrecognized scheme, e.g. rtsp://www.example.com/media.mp4, foo.example.com://bar.example.com/, or :www.example.com@@example.com:80.
  2. Bypass port handling The PORT regex matches the bare ':' with an empty capture, so the old t.length() > 0 guard skips port parsing and drops the ':' without error.
  3. Emit a wrong-host URL WebAddressParser produces a fixed-up URL whose host differs from the input’s apparent host (e.g. http://rtsp//www.example.com/media.mp4), i.e. incorrect reference resolution.
  4. Consume the mis-resolved URL Downstream WebView navigation/comparison acts on the wrong host, potentially routing or attributing the request to an unintended origin (specific downstream security effect is (inferred)).

Impact Assessment

An attacker who controls an address string parsed by WebView’s WebAddressParser can, per the advisory, cause incorrect reference resolution: the parser silently rewrites the host so a URL resolves to a different host than the input indicated. This runs in the WebView/browser-side URL-fixup logic; any concrete escalation such as origin confusion or navigation to an attacker-chosen host is (inferred) and not demonstrated by the patch. There is no indication in the advisory text of in-the-wild exploitation; the class is a logic error (incorrect reference resolution in WebView).

Changed Functions

FunctionChangeNotes
if
android_webview/java/src/org/chromium/android_webview/WebAddressParser.java
modified

Files Changed

  • android_webview/java/src/org/chromium/android_webview/WebAddressParser.java
  • android_webview/junit/src/org/chromium/android_webview/robolectric/WebAddressParserTest.java

Audit Directions

  • Empty-but-non-null capture groups
    Audit regex-driven parsers that gate on length() > 0 (or similar) for delimiter captures; an empty match often means the delimiter was present and is being silently discarded rather than validated.
  • Scheme/host ambiguity in URL fixup
    Review URL “fix-up”/canonicalization paths that proceed when no scheme is recognized, ensuring a stray ':' or delimiter cannot be reinterpreted so the resulting host diverges from the input.
  • Silent normalization vs. rejection
    Look for parsers that repair malformed input by dropping characters instead of throwing; any drop that can alter host/origin interpretation is a reference-resolution bug candidate.
From 57f01d9195a83c45266cf9145f0facefeea9d56e Mon Sep 17 00:00:00 2001
From: Torne (Richard Coles) <torne@google.com>
Date: Fri, 17 Jul 2026 09:05:58 -0700
Subject: [PATCH] webview: Reject ambiguous ':' in WebAddressParser

WebAddressParser's PORT regex accepted a ':' followed by zero digits,
silently dropping it. If no scheme was recognised the colon may have been
intended to be part of a scheme delimiter, and dropping it may change the
interpretation of the URL's host.

Instead, throw URISyntaxException when PORT matched a bare ':' and no scheme
was recognised.

Update WebAddressParserTest; several existing "bad input" test cases now throw,
and add some new cases for unrecognized schemes.

Fixed: 517167020
Change-Id: I090927d8dca336a915c6103ba258c7b65110fb01
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8118007
Reviewed-by: Peter Pakkenberg <pbirk@chromium.org>
Auto-Submit: Richard Coles <torne@chromium.org>
Commit-Queue: Peter Pakkenberg <pbirk@chromium.org>
Commit-Queue: Richard Coles <torne@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1663937}
---
diff --git a/android_webview/java/src/org/chromium/android_webview/WebAddressParser.java b/android_webview/java/src/org/chromium/android_webview/WebAddressParser.java
index b53c87bb..5fab0f33 100644
--- a/android_webview/java/src/org/chromium/android_webview/WebAddressParser.java
+++ b/android_webview/java/src/org/chromium/android_webview/WebAddressParser.java
@@ -77,12 +77,22 @@
             t = m.group(MATCH_GROUP_HOST);
             if (t != null) mHost = t;
             t = m.group(MATCH_GROUP_PORT);
-            if (t != null && t.length() > 0) {
+            if (t != null) {
                 // The ':' character is not returned by the regex.
-                try {
-                    mPort = Integer.parseInt(t);
-                } catch (NumberFormatException ex) {
-                    throw new URISyntaxException(address, "Bad port");
+                if (t.length() == 0) {
+                    // PORT matched a bare ':' with no digits. If no scheme was
+                    // recognised, the ':' may have been a scheme delimiter and
+                    // mHost may not actually be the host, so reject the input
+                    // rather than risk emitting a URL with the wrong host.
+                    if (mScheme.isEmpty()) {
+                        throw new URISyntaxException(address, "Bad port");
+                    }
+                } else {
+                    try {
+                        mPort = Integer.parseInt(t);
+                    } catch (NumberFormatException ex) {
+                        throw new URISyntaxException(address, "Bad port");
+                    }
                 }
             }
             t = m.group(MATCH_GROUP_PATH);
diff --git a/android_webview/junit/src/org/chromium/android_webview/robolectric/WebAddressParserTest.java b/android_webview/junit/src/org/chromium/android_webview/robolectric/WebAddressParserTest.java
index 5e54c91..b8478f5 100644
--- a/android_webview/junit/src/org/chromium/android_webview/robolectric/WebAddressParserTest.java
+++ b/android_webview/junit/src/org/chromium/android_webview/robolectric/WebAddressParserTest.java
@@ -97,13 +97,6 @@
         Assert.assertEquals("http:///.some.domain", fixupUrl(".some.domain"));
         Assert.assertEquals("http:///.some.domain", fixupUrl("http://.some.domain"));
 
-        Assert.assertEquals("http://www.example.com/-1", fixupUrl("www.example.com:-1"));
-        Assert.assertEquals(
-                "http:///www.example.com@@example.com:80",
-                fixupUrl(":www.example.com@@example.com:80"));
-        Assert.assertEquals(
-                "http://rtsp//www.example.com/media.mp4",
-                fixupUrl("rtsp://www.example.com/media.mp4"));
         Assert.assertEquals("http:///^", fixupUrl("^"));
         Assert.assertEquals("http:///.", fixupUrl("."));
         Assert.assertEquals("http:///", fixupUrl(""));
@@ -113,16 +106,26 @@
     @SmallTest
     @Feature({"AndroidWebView", "Privacy"})
     public void testInputWithURISyntaxException() {
-        try {
-            fixupUrl("www.example.com:1234567890123");
-            Assert.fail("Bad port should throw an exception");
-        } catch (URISyntaxException e) {
-        }
+        assertBadAddress("www.example.com:1234567890123");
+
+        // A ':' that isn't followed by a port number and isn't preceded by a recognised scheme
+        // is rejected, since it may have been intended as a scheme delimiter and the parser
+        // can't determine the host with confidence.
+        assertBadAddress("www.example.com:-1");
+        assertBadAddress(":www.example.com@@example.com:80");
+        assertBadAddress("rtsp://www.example.com/media.mp4");
+        assertBadAddress("foo.example.com://bar.example.com/");
+        assertBadAddress("foo.example.com://x@bar.example.com/");
+        assertBadAddress("a.example.com://b.example.com/path");
 
         // Because the ANCHOR regex matches everything, WebAddressParser won't throw exception
         // because of no matching.
     }
 
+    private void assertBadAddress(String url) {
+        Assert.assertThrows(URISyntaxException.class, () -> fixupUrl(url));
+    }
+
     private String fixupUrl(String url) throws URISyntaxException {
         return new WebAddressParser(url).toString();
     }
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.