Medium chrome UAF 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Google Lens
DescriptionUse after free in Google Lens
ComponentGoogle Lens
Sub-componentLens
Bug ClassUAF
Tracker561921279
Fix commitd9a90b84f593 (chromium/src) +92/-6
CISA KEVNot listed
CreditedOGINOME Tomohito
Disclosed2026-10-20

Changed Functions

FunctionChangeNotes
TEST_F
chrome/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.cc
  • chrome/common/extensions/api/_api_features.json
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.