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 <[email protected]> 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 <[email protected]> Commit-Queue: Duncan Mercer <[email protected]> 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