Chrome · Google Lens › Lens
CVE-2026-113221
UAF in Google Lens (Lens)
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fchrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc |
modified |
Files Changed
chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.ccchrome/common/extensions/api/_api_features.json
Patch
From d9a90b84f593d575b280ef956036cf935d76caa2 Mon Sep 17 00:00:00 2001
From: Duncan Mercer <mercerd@google.com>
Date: Wed, 16 Sep 2026 15:46:39 -0700
Subject: [PATCH] [Lens] Restrict languageSettingsPrivate access
Currently, chrome-untrusted://lens-overlay/* is granted access to
the entire languageSettingsPrivate namespace in _api_features.json.
This unnecessarily exposes privileged extension APIs, such as custom
spellcheck dictionary methods (getSpellcheckWords, addSpellcheckWord,
etc.), to the untrusted lens-overlay WebUI context.
The Lens overlay UI only requires getLanguageList and
getTranslateTargetLanguage.
This CL scopes the webui_untrusted grant down to only those two child
features, while ensuring that privileged_extension and trusted webui
(chrome://settings/* and chrome://os-settings/*) maintain access to
the full API without inheriting unnecessary permissions.
Fixed: 561921279
Change-Id: I4b6aff0173e1ef652987980c06be23b3aa7de8ae
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8415547
Reviewed-by: Tim <tjudkins@chromium.org>
Commit-Queue: Duncan Mercer <mercerd@google.com>
Cr-Commit-Position: refs/heads/main@{#1699320}
---
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 0d58377..2717913 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -629,7 +629,8 @@
},
"languageSettingsPrivate": [{
"dependencies": ["permission:languageSettingsPrivate"],
- "contexts": ["privileged_extension"]
+ "contexts": ["privileged_extension"],
+ "default_parent": true
}, {
"channel": "stable",
"contexts": ["webui"],
@@ -639,12 +640,42 @@
"chrome://os-settings/*",
"chrome://settings/*"
]
- },
- {
+ }],
+ // chrome-untrusted://lens-overlay only needs getLanguageList and
+ // getTranslateTargetLanguage; grant them individually instead of the whole
+ // namespace (crbug.com/561921279).
+ "languageSettingsPrivate.getLanguageList": [{
+ "contexts": ["privileged_extension"]
+ }, {
"channel": "stable",
- "contexts": [
- "webui_untrusted"
- ],
+ "contexts": ["webui"],
+ "dependencies": [],
+ "matches": [
+ "chrome://os-settings/*",
+ "chrome://settings/*"
+ ]
+ }, {
+ "channel": "stable",
+ "contexts": ["webui_untrusted"],
+ "dependencies": [],
+ "matches": [
+ "chrome-untrusted://lens-overlay/*"
+ ]
+ }],
+ "languageSettingsPrivate.getTranslateTargetLanguage": [{
+ "contexts": ["privileged_extension"]
+ }, {
+ "channel": "stable",
+ "contexts": ["webui"],
+ "dependencies": [],
+ "matches": [
+ "chrome://os-settings/*",
+ "chrome://settings/*"
+ ]
+ }, {
+ "channel": "stable",
+ "contexts": ["webui_untrusted"],
+ "dependencies": [],
"matches": [
"chrome-untrusted://lens-overlay/*"
]
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
index 3604b45..04fe335c 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
@@ -36,6 +36,8 @@
#include "extensions/browser/api_test_utils.h"
#include "extensions/browser/event_router_factory.h"
#include "extensions/browser/extension_prefs.h"
+#include "extensions/common/mojom/context_type.mojom.h"
+#include "url/gurl.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_features.h"
@@ -292,6 +294,59 @@
}
}
+namespace {
+
+template <typename T>
+bool HasPermission(mojom::ContextType context_type, const GURL& url) {
+ auto function = base::MakeRefCounted<T>();
+ function->SetName(function->static_function_name());
+ function->set_source_context_type(context_type);
+ function->set_source_url(url);
+ return function->HasPermission();
+}
+
+} // namespace
+
+TEST_F(LanguageSettingsPrivateApiTest, FunctionPermissions) {
+ const GURL kLensOverlayUrl("chrome-untrusted://lens-overlay/");
+ const GURL kSettingsUrl("chrome://settings/");
+ const GURL kOtherUntrustedUrl("chrome-untrusted://other/");
+
+ // chrome-untrusted://lens-overlay/ should have permission for getLanguageList
+ // and getTranslateTargetLanguage.
+ EXPECT_TRUE(HasPermission<LanguageSettingsPrivateGetLanguageListFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_TRUE(
+ HasPermission<LanguageSettingsPrivateGetTranslateTargetLanguageFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+
+ // chrome-untrusted://lens-overlay/ should NOT have permission for other
+ // languageSettingsPrivate functions like spellcheck or dictionary functions
+ // (crbug.com/561921279).
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateGetSpellcheckWordsFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateAddSpellcheckWordFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_FALSE(
+ HasPermission<LanguageSettingsPrivateRemoveSpellcheckWordFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateEnableLanguageFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+
+ // chrome://settings/ should have permission for all of these functions.
+ EXPECT_TRUE(HasPermission<LanguageSettingsPrivateGetLanguageListFunction>(
+ mojom::ContextType::kWebUi, kSettingsUrl));
+ EXPECT_TRUE(
+ HasPermission<LanguageSettingsPrivateGetTranslateTargetLanguageFunction>(
+ mojom::ContextType::kWebUi, kSettingsUrl));
+ EXPECT_TRUE(HasPermission<LanguageSettingsPrivateGetSpellcheckWordsFunction>(
+ mojom::ContextType::kWebUi, kSettingsUrl));
+
+ // Other untrusted WebUI should NOT have permission.
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateGetLanguageListFunction>(
+ mojom::ContextType::kUntrustedWebUi, kOtherUntrustedUrl));
+}
+
void LanguageSettingsPrivateApiTest::RunGetLanguageListTest() {
struct LanguageToTest {
std::string accept_language;
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
index 3604b45..04fe335c 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
@@ -36,6 +36,8 @@
#include "extensions/browser/api_test_utils.h"
#include "extensions/browser/event_router_factory.h"
#include "extensions/browser/extension_prefs.h"
+#include "extensions/common/mojom/context_type.mojom.h"
+#include "url/gurl.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_features.h"
@@ -292,6 +294,59 @@
}
}
+namespace {
+
+template <typename T>
+bool HasPermission(mojom::ContextType context_type, const GURL& url) {
+ auto function = base::MakeRefCounted<T>();
+ function->SetName(function->static_function_name());
+ function->set_source_context_type(context_type);
+ function->set_source_url(url);
+ return function->HasPermission();
+}
+
+} // namespace
+
+TEST_F(LanguageSettingsPrivateApiTest, FunctionPermissions) {
+ const GURL kLensOverlayUrl("chrome-untrusted://lens-overlay/");
+ const GURL kSettingsUrl("chrome://settings/");
+ const GURL kOtherUntrustedUrl("chrome-untrusted://other/");
+
+ // chrome-untrusted://lens-overlay/ should have permission for getLanguageList
+ // and getTranslateTargetLanguage.
+ EXPECT_TRUE(HasPermission<LanguageSettingsPrivateGetLanguageListFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_TRUE(
+ HasPermission<LanguageSettingsPrivateGetTranslateTargetLanguageFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+
+ // chrome-untrusted://lens-overlay/ should NOT have permission for other
+ // languageSettingsPrivate functions like spellcheck or dictionary functions
+ // (crbug.com/561921279).
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateGetSpellcheckWordsFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateAddSpellcheckWordFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_FALSE(
+ HasPermission<LanguageSettingsPrivateRemoveSpellcheckWordFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateEnableLanguageFunction>(
+ mojom::ContextType::kUntrustedWebUi, kLensOverlayUrl));
+
+ // chrome://settings/ should have permission for all of these functions.
+ EXPECT_TRUE(HasPermission<LanguageSettingsPrivateGetLanguageListFunction>(
+ mojom::ContextType::kWebUi, kSettingsUrl));
+ EXPECT_TRUE(
+ HasPermission<LanguageSettingsPrivateGetTranslateTargetLanguageFunction>(
+ mojom::ContextType::kWebUi, kSettingsUrl));
+ EXPECT_TRUE(HasPermission<LanguageSettingsPrivateGetSpellcheckWordsFunction>(
+ mojom::ContextType::kWebUi, kSettingsUrl));
+
+ // Other untrusted WebUI should NOT have permission.
+ EXPECT_FALSE(HasPermission<LanguageSettingsPrivateGetLanguageListFunction>(
+ mojom::ContextType::kUntrustedWebUi, kOtherUntrustedUrl));
+}
+
void LanguageSettingsPrivateApiTest::RunGetLanguageListTest() {
struct LanguageToTest {
std::string accept_language;
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