Chrome · Google Lens
CVE-2026-8550
UAF in Google Lens
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
chrome/browser/ui/lens/lens_overlay_query_controller.ccchrome/browser/ui/lens/lens_overlay_query_controller.h
Patch
From 4af1bce9f2ecb4ad514d3fc4e3f170f707180ced Mon Sep 17 00:00:00 2001
From: Duncan Mercer <mercerd@google.com>
Date: Thu, 02 Apr 2026 12:29:55 -0700
Subject: [PATCH] [Lens Overlay] Fix Use-After-Free in query controller
Pass PageContent by value to background threads to ensure lifetime
safety. Also fix task cancellation bypass and state reset.
Fixed: 498322453
Change-Id: If2282782cf97630604f5e6220666035f0294c989
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7723469
Reviewed-by: Juan Mojica <juanmojica@google.com>
Commit-Queue: Duncan Mercer <mercerd@google.com>
Cr-Commit-Position: refs/heads/main@{#1609432}
---
diff --git a/chrome/browser/ui/lens/lens_overlay_query_controller.cc b/chrome/browser/ui/lens/lens_overlay_query_controller.cc
index 24a417ab..789cffd0 100644
--- a/chrome/browser/ui/lens/lens_overlay_query_controller.cc
+++ b/chrome/browser/ui/lens/lens_overlay_query_controller.cc
@@ -297,7 +297,6 @@
// Returns the lens::Payload to be sent after uploading chunked data using the
// repeated Content field instead of the deprecated payload fields.
lens::Payload CreatePageContentPayloadForChunks(
- base::span<const lens::PageContent> page_content,
lens::MimeType primary_content_type,
GURL page_url,
std::optional<std::string> page_title,
@@ -328,7 +327,7 @@
// Returns the lens::Payload using the repeated Content field instead of the
// deprecated payload fields.
lens::Payload CreatePageContentPayload(
- base::span<const lens::PageContent> page_contents,
+ std::vector<lens::PageContent> page_contents,
GURL page_url,
std::optional<std::string> page_title) {
lens::Payload payload;
@@ -505,6 +504,7 @@
page_url_ = GURL();
page_title_ = std::nullopt;
partial_content_ = base::span<const std::u16string>();
+ page_content_request_in_progress_ = false;
}
void LensOverlayQueryController::SendUpdatedPageContent(
@@ -1270,13 +1270,13 @@
return;
}
+ compression_task_tracker_->TryCancelAll();
+
if (underlying_page_contents_.empty() ||
underlying_page_contents_.front().bytes_.empty()) {
// No need to send the request without underlying content bytes.
return;
}
-
- compression_task_tracker_->TryCancelAll();
page_contents_request_start_time_ = base::TimeTicks::Now();
page_content_request_in_progress_ = true;
chunk_upload_in_progress_ = false;
@@ -1318,9 +1318,11 @@
} else {
// Post CreatePageContentPayload to a task off the main thread so
// compression does not throttle the main thread.
+ std::vector<lens::PageContent> contents_copy(
+ underlying_page_contents_.begin(), underlying_page_contents_.end());
compression_task_tracker_->PostTaskAndReplyWithResult(
compression_task_runner_.get(), FROM_HERE,
- base::BindOnce(&CreatePageContentPayload, underlying_page_contents_,
+ base::BindOnce(&CreatePageContentPayload, std::move(contents_copy),
page_url_, page_title_),
base::BindOnce(
&LensOverlayQueryController::PrepareAndFetchPageContentRequestPart2,
@@ -1416,9 +1418,8 @@
base::SequencedTaskRunner::GetCurrentDefault()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&CreatePageContentPayloadForChunks,
- underlying_page_contents_, primary_content_type_,
- page_url_, page_title_, total_chunks,
- retrying_page_content_upload_),
+ primary_content_type_, page_url_, page_title_,
+ total_chunks, retrying_page_content_upload_),
base::BindOnce(
&LensOverlayQueryController::PrepareAndFetchPageContentRequestPart2,
weak_ptr_factory_.GetWeakPtr(), request_id));
diff --git a/chrome/browser/ui/lens/lens_overlay_query_controller.h b/chrome/browser/ui/lens/lens_overlay_query_controller.h
index 20302998..a9877b2 100644
--- a/chrome/browser/ui/lens/lens_overlay_query_controller.h
+++ b/chrome/browser/ui/lens/lens_overlay_query_controller.h
@@ -199,7 +199,8 @@
lens::mojom::SemanticEvent event);
bool IsPageContentUploadInProgress() const {
- return page_content_endpoint_fetcher_.get() != nullptr;
+ return page_content_request_in_progress_ ||
+ page_content_endpoint_fetcher_.get() != nullptr;
}
// Returns whether the query controller is off.
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