Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in ORB
DescriptionInappropriate implementation in ORB
ComponentORB
Bug ClassLogic Error
Tracker527665262
Fix commit2385fa689a02 (chromium/src) +27/-4
CISA KEVNot listed
CreditedSharkkcode
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
if
services/network/orb/orb_sniffers.cc
modified
for
services/network/orb/orb_sniffers_unittest.cc
modified
TEST
services/network/orb/orb_sniffers_unittest.cc
modified

Files Changed

  • services/network/orb/orb_sniffers.cc
  • services/network/orb/orb_sniffers_unittest.cc
From 2385fa689a02678b5e71fc47a8d8da095875c062 Mon Sep 17 00:00:00 2001
From: Lukasz Anforowicz <[email protected]>
Date: Fri, 26 Jun 2026 09:57:21 -0700
Subject: [PATCH] [orb] Treat `'\f'` character as whitespace in ORB sniffing.

Fixed: 527665262
Change-Id: Ic6e8a79d429190987ef40ef5f1707928997b46d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8007929
Reviewed-by: Daniel Vogelheim <[email protected]>
Commit-Queue: Łukasz Anforowicz <[email protected]>
Auto-Submit: Łukasz Anforowicz <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1653232}
---

diff --git a/services/network/orb/orb_sniffers.cc b/services/network/orb/orb_sniffers.cc
index d3e27a0..d230ba5 100644
--- a/services/network/orb/orb_sniffers.cc
+++ b/services/network/orb/orb_sniffers.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 #include <set>
 #include <string>
+#include <string_view>
 #include <unordered_set>
 #include <vector>
 
@@ -34,8 +35,11 @@
   }
 }
 
+// Based on https://infra.spec.whatwg.org/#ascii-whitespace
+const std::string_view kWhitespaceChars = "\t\n\f\r ";
+
 void AdvancePastWhitespace(std::string_view* data) {
-  size_t offset = data->find_first_not_of(" \t\r\n");
+  size_t offset = data->find_first_not_of(kWhitespaceChars);
   if (offset == std::string_view::npos) {
     // |data| was entirely whitespace.
     *data = std::string_view();
@@ -232,7 +236,7 @@
     const char c = data[i];
     if (state != kLeftQuoteState && state != kEscapeState) {
       // Whitespace is ignored (outside of string literals)
-      if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+      if (kWhitespaceChars.contains(c)) {
         continue;
       }
     }
diff --git a/services/network/orb/orb_sniffers_unittest.cc b/services/network/orb/orb_sniffers_unittest.cc
index 507142d..8a3445f 100644
--- a/services/network/orb/orb_sniffers_unittest.cc
+++ b/services/network/orb/orb_sniffers_unittest.cc
@@ -30,6 +30,25 @@
   EXPECT_EQ(SniffingResult::kYes,
             SniffForHTML(" <!-- this is comment -->\n<html><body>"));
 
+  // All whitespace characters listed by
+  // https://infra.spec.whatwg.org/#ascii-whitespace
+  // (regression test for https://crbug.com/527665262).
+  const std::array<std::pair<std::string_view, std::string_view>, 5>
+      kWhitespaceStrings{{
+          {"\u0009", "tab"},
+          {"\u000a", "lf"},
+          {"\u000c", "ff"},
+          {"\u000d", "cr"},
+          {"\u0020", "space"},
+      }};
+  for (const auto& kTestInput : kWhitespaceStrings) {
+    SCOPED_TRACE(testing::Message() << "Testing `" << kTestInput.second << "`");
+    std::string input;
+    input += kTestInput.first;
+    input += "<html>";
+    EXPECT_EQ(SniffingResult::kYes, SniffForHTML(input));
+  }
+
   // HTML comment, whitespace, more HTML comments, HTML tags.
   EXPECT_EQ(
       SniffingResult::kYes,
@@ -116,7 +135,7 @@
 
 TEST(OrbSnifferTest, SniffForXML) {
   std::string_view xml_data(
-      "   \t \r \n     <?xml version=\"1.0\"?>\n <catalog");
+      "   \t \r \n \f    <?xml version=\"1.0\"?>\n <catalog");
   std::string_view non_xml_data("        var name=window.location;\nadfadf");
   std::string_view empty_data("");
 
@@ -135,7 +154,7 @@
 TEST(OrbSnifferTest, SniffForJSON) {
   std::string_view json_data("\t\t\r\n   { \"name\" : \"chrome\", ");
   std::string_view json_corrupt_after_first_key(
-      "\t\t\r\n   { \"name\" :^^^^!!@#\1\", ");
+      "\t\t\r\n\f   { \"name\" :^^^^!!@#\1\", ");
   std::string_view json_data2("{ \"key   \\\"  \"          \t\t\r\n:");
   std::string_view non_json_data0("\t\t\r\n   { name : \"chrome\", ");
   std::string_view non_json_data1("\t\t\r\n   foo({ \"name\" : \"chrome\", ");
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/services/network/orb/orb_sniffers_unittest.cc b/services/network/orb/orb_sniffers_unittest.cc
index 507142d..8a3445f 100644
--- a/services/network/orb/orb_sniffers_unittest.cc
+++ b/services/network/orb/orb_sniffers_unittest.cc
@@ -30,6 +30,25 @@
   EXPECT_EQ(SniffingResult::kYes,
             SniffForHTML(" <!-- this is comment -->\n<html><body>"));
 
+  // All whitespace characters listed by
+  // https://infra.spec.whatwg.org/#ascii-whitespace
+  // (regression test for https://crbug.com/527665262).
+  const std::array<std::pair<std::string_view, std::string_view>, 5>
+      kWhitespaceStrings{{
+          {"\u0009", "tab"},
+          {"\u000a", "lf"},
+          {"\u000c", "ff"},
+          {"\u000d", "cr"},
+          {"\u0020", "space"},
+      }};
+  for (const auto& kTestInput : kWhitespaceStrings) {
+    SCOPED_TRACE(testing::Message() << "Testing `" << kTestInput.second << "`");
+    std::string input;
+    input += kTestInput.first;
+    input += "<html>";
+    EXPECT_EQ(SniffingResult::kYes, SniffForHTML(input));
+  }
+
   // HTML comment, whitespace, more HTML comments, HTML tags.
   EXPECT_EQ(
       SniffingResult::kYes,
@@ -116,7 +135,7 @@
 
 TEST(OrbSnifferTest, SniffForXML) {
   std::string_view xml_data(
-      "   \t \r \n     <?xml version=\"1.0\"?>\n <catalog");
+      "   \t \r \n \f    <?xml version=\"1.0\"?>\n <catalog");
   std::string_view non_xml_data("        var name=window.location;\nadfadf");
   std::string_view empty_data("");
 
@@ -135,7 +154,7 @@
 TEST(OrbSnifferTest, SniffForJSON) {
   std::string_view json_data("\t\t\r\n   { \"name\" : \"chrome\", ");
   std::string_view json_corrupt_after_first_key(
-      "\t\t\r\n   { \"name\" :^^^^!!@#\1\", ");
+      "\t\t\r\n\f   { \"name\" :^^^^!!@#\1\", ");
   std::string_view json_data2("{ \"key   \\\"  \"          \t\t\r\n:");
   std::string_view non_json_data0("\t\t\r\n   { name : \"chrome\", ");
   std::string_view non_json_data1("\t\t\r\n   foo({ \"name\" : \"chrome\", ");
Loading diff…

Original Bug Report

reported by [email protected]

ORB bypass: \x0C prefix prevents cross-origin HTML detection, leaking response body to renderer


Report description

ORB bypass: \x0C prefix prevents cross-origin HTML detection, leaking response body to renderer


Bug location

Where do you want to report your vulnerability?

Chrome VRP – Report security issues affecting the Chrome browser. See program rules

Which URL (or repository) have you found the vulnerability in?

https://source.chromium.org/chromium/chromium/src/+/main:services/network/orb/orb_sniffers.cc


The problem

Please describe the technical details of the vulnerability

Root Cause

services/network/orb/orb_sniffers.ccAdvancePastWhitespace():

void AdvancePastWhitespace(std::string_view* data) {
  size_t offset = data->find_first_not_of(" \t\r\n");  // Missing: \x0C (Form Feed)
}

HTML5 Section 2.4.1 defines whitespace as: U+0020, U+0009, U+000A, U+000C, U+000D. ORB’s set is missing U+000C. A single \x0C byte prefixed to a cross-origin text/plain response prevents ORB from detecting HTML/JSON/XML signatures — full response body enters the renderer process.

Reproduction

  1. Place poc.html and poc.py in the same directory
  2. Run python poc.py
  3. Open Chrome to http://localhost:8080
  4. Page shows:
    • /normal (no prefix): BLOCKED
    • /bypass (0x0C prefix): LOADED
  5. DevTools → Network tab → click bypass → Response tab → shows SSN 123-45-6789

Suggested Fix

void AdvancePastWhitespace(std::string_view* data) {
  size_t offset = data->find_first_not_of(" \t\r\n\f");  // Add \f (Form Feed)
}

Tested on: Chrome 151.0.7909.0 (Canary, Windows, 2026-06-24)

Impact analysis

Any web attacker can steal cross-origin response data (session tokens, PII, API responses) from sites where the victim is logged in. No special privileges needed — victim only has to visit the attacker’s page.

Under Chrome’s Spectre threat model, all data that enters renderer memory is considered extractable. This bypass lets the full response body in.

Same vulnerability class as CVE-2026-7971 (orb_sniffers.cc).


The cause

What version of Chrome have you found the security issue in?

151.0.7909.0 Canary

No, it is not related to a crash.

Choose the type of vulnerability

Site Isolation Bypass

How would you like to be publicly acknowledged for your report?

Sharkkcode

View on issue tracker