Chrome · Receiver
CVE-2026-17776
Logic Error in Receiver
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forcomponents/url_rewrite/common/url_loader_throttle.cc |
modified | |
ifcomponents/url_rewrite/common/url_loader_throttle.cc |
modified | |
TEST_Fcomponents/url_rewrite/common/url_loader_throttle_unittest.cc |
modified |
Files Changed
components/url_rewrite/common/url_loader_throttle.cccomponents/url_rewrite/common/url_loader_throttle_unittest.cc
Patch
From 3bf03fd44bc60a251de356c5010e2172d7d84923 Mon Sep 17 00:00:00 2001
From: Muyao Xu <muyaoxu@google.com>
Date: Wed, 24 Jun 2026 12:04:10 -0700
Subject: [PATCH] Always Reevaluate access policies if a rule changes the URL
URLLoaderThrottle was evaluating embedder-defined access policies
(kAllow/kDeny) only once on the initial request URL. If rewrite rules
were applied sequentially, a rule could mutate the URL to a denied host
without triggering a policy re-check.
This CL updates WillStartRequest to re-evaluate the access policy on the
mutated request URL if a rule changes the URL.
Bug: 513404032
Change-Id: Ie251b72920383cc0e94334e17a2bc19af93f40e3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7923228
Reviewed-by: David Song <wintermelons@google.com>
Commit-Queue: Muyao Xu <muyaoxu@google.com>
Cr-Commit-Position: refs/heads/main@{#1651875}
---
diff --git a/components/url_rewrite/common/url_loader_throttle.cc b/components/url_rewrite/common/url_loader_throttle.cc
index 8579d1b..5eca3303 100644
--- a/components/url_rewrite/common/url_loader_throttle.cc
+++ b/components/url_rewrite/common/url_loader_throttle.cc
@@ -193,8 +193,18 @@
return;
}
- for (const auto& rule : rules_->data->rules)
+ GURL current_url = request->url;
+ for (const auto& rule : rules_->data->rules) {
ApplyRule(request, rule);
+ if (request->url != current_url) {
+ if (!IsRequestAllowed(request, rules_->data)) {
+ delegate_->CancelWithError(net::ERR_ABORTED,
+ "Resource load blocked by embedder policy.");
+ return;
+ }
+ current_url = request->url;
+ }
+ }
if (!added_headers_.empty()) {
original_origin_ = url::Origin::Create(request->url);
diff --git a/components/url_rewrite/common/url_loader_throttle_unittest.cc b/components/url_rewrite/common/url_loader_throttle_unittest.cc
index f4f062b..4646160e 100644
--- a/components/url_rewrite/common/url_loader_throttle_unittest.cc
+++ b/components/url_rewrite/common/url_loader_throttle_unittest.cc
@@ -408,4 +408,49 @@
}
}
+TEST_F(URLLoaderThrottleTest, ReplaceUrlReevaluatesPolicy) {
+ mojom::UrlRequestRewriteRulesPtr rules = mojom::UrlRequestRewriteRules::New();
+
+ {
+ mojom::UrlRequestRewriteReplaceUrlPtr replace_url =
+ mojom::UrlRequestRewriteReplaceUrl::New();
+ replace_url->url_ends_with = "/partner-endpoint";
+ replace_url->new_url = GURL("http://internal.host/api");
+
+ mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
+ rule->hosts_filter =
+ std::optional<std::vector<std::string>>({"allowed.com"});
+ rule->actions.push_back(
+ mojom::UrlRequestAction::NewReplaceUrl(std::move(replace_url)));
+ rules->rules.push_back(std::move(rule));
+ }
+
+ {
+ mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
+ rule->hosts_filter =
+ std::optional<std::vector<std::string>>({"internal.host"});
+ rule->actions.push_back(mojom::UrlRequestAction::NewPolicy(
+ mojom::UrlRequestAccessPolicy::kDeny));
+ rules->rules.push_back(std::move(rule));
+ }
+
+ TestThrottleDelegate delegate;
+ URLLoaderThrottle throttle(
+ base::MakeRefCounted<UrlRequestRewriteRules>(std::move(rules)),
+ CreateCorsExemptHeadersCallback({}));
+ throttle.set_delegate(&delegate);
+
+ bool unused_defer = false;
+
+ // Request to allowed.com/partner-endpoint should be rewritten to
+ // internal.host, which is denied, thus the request should be canceled.
+ network::ResourceRequest request;
+ request.url = GURL("http://allowed.com/partner-endpoint?q=ATTACKER");
+ throttle.WillStartRequest(&request, &unused_defer);
+
+ EXPECT_TRUE(delegate.canceled());
+ EXPECT_EQ(delegate.cancel_reason(),
+ "Resource load blocked by embedder policy.");
+}
+
} // namespace url_rewrite
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/components/url_rewrite/common/url_loader_throttle_unittest.cc b/components/url_rewrite/common/url_loader_throttle_unittest.cc
index f4f062b..4646160e 100644
--- a/components/url_rewrite/common/url_loader_throttle_unittest.cc
+++ b/components/url_rewrite/common/url_loader_throttle_unittest.cc
@@ -408,4 +408,49 @@
}
}
+TEST_F(URLLoaderThrottleTest, ReplaceUrlReevaluatesPolicy) {
+ mojom::UrlRequestRewriteRulesPtr rules = mojom::UrlRequestRewriteRules::New();
+
+ {
+ mojom::UrlRequestRewriteReplaceUrlPtr replace_url =
+ mojom::UrlRequestRewriteReplaceUrl::New();
+ replace_url->url_ends_with = "/partner-endpoint";
+ replace_url->new_url = GURL("http://internal.host/api");
+
+ mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
+ rule->hosts_filter =
+ std::optional<std::vector<std::string>>({"allowed.com"});
+ rule->actions.push_back(
+ mojom::UrlRequestAction::NewReplaceUrl(std::move(replace_url)));
+ rules->rules.push_back(std::move(rule));
+ }
+
+ {
+ mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
+ rule->hosts_filter =
+ std::optional<std::vector<std::string>>({"internal.host"});
+ rule->actions.push_back(mojom::UrlRequestAction::NewPolicy(
+ mojom::UrlRequestAccessPolicy::kDeny));
+ rules->rules.push_back(std::move(rule));
+ }
+
+ TestThrottleDelegate delegate;
+ URLLoaderThrottle throttle(
+ base::MakeRefCounted<UrlRequestRewriteRules>(std::move(rules)),
+ CreateCorsExemptHeadersCallback({}));
+ throttle.set_delegate(&delegate);
+
+ bool unused_defer = false;
+
+ // Request to allowed.com/partner-endpoint should be rewritten to
+ // internal.host, which is denied, thus the request should be canceled.
+ network::ResourceRequest request;
+ request.url = GURL("http://allowed.com/partner-endpoint?q=ATTACKER");
+ throttle.WillStartRequest(&request, &unused_defer);
+
+ EXPECT_TRUE(delegate.canceled());
+ EXPECT_EQ(delegate.cancel_reason(),
+ "Resource load blocked by embedder policy.");
+}
+
} // namespace url_rewrite
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.
References
On This Page