CVE-2026-17897
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifservices/network/orb/orb_sniffers.cc |
modified | |
forservices/network/orb/orb_sniffers_unittest.cc |
modified | |
TESTservices/network/orb/orb_sniffers_unittest.cc |
modified |
Files Changed
services/network/orb/orb_sniffers.ccservices/network/orb/orb_sniffers_unittest.cc
Patch
From 2385fa689a02678b5e71fc47a8d8da095875c062 Mon Sep 17 00:00:00 2001
From: Lukasz Anforowicz <lukasza@chromium.org>
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 <vogelheim@chromium.org>
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
Auto-Submit: Łukasz Anforowicz <lukasza@chromium.org>
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\", ");
Regression Test / PoC
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\", ");
Original Bug Report
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.cc — AdvancePastWhitespace():
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
- Place
poc.htmlandpoc.pyin the same directory - Run
python poc.py - Open Chrome to
http://localhost:8080 - Page shows:
/normal(no prefix): BLOCKED/bypass(0x0C prefix): LOADED
- DevTools → Network tab → click
bypass→ Response tab → showsSSN 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
Is the security issue related to a crash?
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