CVE-2025-3070
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fextensions/browser/api/content_settings/content_settings_store_unittest.cc |
modified |
Files Changed
extensions/browser/api/content_settings/content_settings_store.ccextensions/browser/api/content_settings/content_settings_store_unittest.ccextensions/test/DEPSextensions/test/extensions_unittests_main.cctools/metrics/histograms/metadata/extensions/histograms.xml
Patch
From 34a2937e30659b6d5616d881f3be0f93b4a59c47 Mon Sep 17 00:00:00 2001
From: Emily Stark <estark@google.com>
Date: Thu, 29 Aug 2024 04:11:21 +0000
Subject: [PATCH] Add metrics for chrome.contentSettings extension usage
This CL adds metrics for how often chrome-extension:// origins are
used to set content settings via the chrome.contentSettings API, to
see if this can be deprecated.
Bug: 40086360
Change-Id: Ide2b22a6e628fd8bebbd227032e5e4c7264c1c1d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5814282
Reviewed-by: Balazs Engedy <engedy@chromium.org>
Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org>
Reviewed-by: Kelvin Jiang <kelvinjiang@chromium.org>
Commit-Queue: Emily Stark <estark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1348438}
---
diff --git a/extensions/browser/api/content_settings/content_settings_store.cc b/extensions/browser/api/content_settings/content_settings_store.cc
index 9a038a3..62a0ac0 100644
--- a/extensions/browser/api/content_settings/content_settings_store.cc
+++ b/extensions/browser/api/content_settings/content_settings_store.cc
@@ -147,6 +147,18 @@
ContentSettingsType type,
ContentSetting setting,
ChromeSettingScope scope) {
+ if (primary_pattern.GetScheme() ==
+ ContentSettingsPattern::SCHEME_CHROMEEXTENSION) {
+ content_settings_uma_util::RecordContentSettingsHistogram(
+ "Extensions.ContentSettings.PrimaryPatternChromeExtensionScheme", type);
+ }
+ if (secondary_pattern.GetScheme() ==
+ ContentSettingsPattern::SCHEME_CHROMEEXTENSION) {
+ content_settings_uma_util::RecordContentSettingsHistogram(
+ "Extensions.ContentSettings.SecondaryPatternChromeExtensionScheme",
+ type);
+ }
+
if (primary_pattern == ContentSettingsPattern::Wildcard()) {
if (secondary_pattern == ContentSettingsPattern::Wildcard()) {
content_settings_uma_util::RecordContentSettingsHistogram(
diff --git a/extensions/browser/api/content_settings/content_settings_store_unittest.cc b/extensions/browser/api/content_settings/content_settings_store_unittest.cc
index d064d6c..117be00 100644
--- a/extensions/browser/api/content_settings/content_settings_store_unittest.cc
+++ b/extensions/browser/api/content_settings/content_settings_store_unittest.cc
@@ -8,10 +8,12 @@
#include <memory>
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
+#include "components/content_settings/core/browser/content_settings_uma_util.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_utils.h"
@@ -349,6 +351,39 @@
store()->RemoveObserver(&observer);
}
+TEST_F(ContentSettingsStoreTest, ChromeExtensionSchemeMetrics) {
+ base::HistogramTester histogram_tester;
+ content_settings::ContentSettingsRegistry::GetInstance();
+ std::string extension_id(32, 'a');
+ ContentSettingsPattern chrome_extension_pattern =
+ ContentSettingsPattern::FromString(
+ "chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/");
+ ContentSettingsPattern https_pattern =
+ ContentSettingsPattern::FromString("https://example.test/");
+
+ RegisterExtension(extension_id);
+ store()->SetExtensionContentSetting(
+ extension_id, chrome_extension_pattern, https_pattern,
+ ContentSettingsType::COOKIES, CONTENT_SETTING_ALLOW,
+ ChromeSettingScope::kRegular);
+ histogram_tester.ExpectUniqueSample(
+ "Extensions.ContentSettings.PrimaryPatternChromeExtensionScheme",
+ content_settings_uma_util::ContentSettingTypeToHistogramValue(
+ ContentSettingsType::COOKIES),
+ 1);
+
+ RegisterExtension(extension_id);
+ store()->SetExtensionContentSetting(
+ extension_id, https_pattern, chrome_extension_pattern,
+ ContentSettingsType::IMAGES, CONTENT_SETTING_ALLOW,
+ ChromeSettingScope::kRegular);
+ histogram_tester.ExpectUniqueSample(
+ "Extensions.ContentSettings.SecondaryPatternChromeExtensionScheme",
+ content_settings_uma_util::ContentSettingTypeToHistogramValue(
+ ContentSettingsType::IMAGES),
+ 1);
+}
+
TEST_F(ContentSettingsStoreTest, SetExtensionContentSettingFromList) {
content_settings::ContentSettingsRegistry::GetInstance();
diff --git a/extensions/test/DEPS b/extensions/test/DEPS
index d70103cd..0b22280d 100644
--- a/extensions/test/DEPS
+++ b/extensions/test/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/content_settings/core/common",
"+content/public",
"+ui/aura/test",
"+ui/gl",
diff --git a/extensions/test/extensions_unittests_main.cc b/extensions/test/extensions_unittests_main.cc
index d9e86fa1..ce77637d 100644
--- a/extensions/test/extensions_unittests_main.cc
+++ b/extensions/test/extensions_unittests_main.cc
@@ -10,6 +10,7 @@
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_io_thread.h"
#include "build/buildflag.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
#include "content/public/common/content_client.h"
#include "content/public/test/content_test_suite_base.h"
#include "content/public/test/unittest_test_suite.h"
@@ -22,6 +23,9 @@
namespace {
+const char* const kNonWildcardDomainNonPortSchemes[] = {
+ extensions::kExtensionScheme};
+
// Content client that exists only to register chrome-extension:// scheme with
// the url module.
// TODO(jamescook): Should this be merged with ShellContentClient? Should this
@@ -69,6 +73,9 @@
{
ExtensionsContentClient content_client;
RegisterContentSchemes(&content_client);
+ ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(
+ kNonWildcardDomainNonPortSchemes,
+ std::size(kNonWildcardDomainNonPortSchemes));
}
RegisterInProcessThreads();
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index f74087d..4645bffc 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -410,8 +410,24 @@
</histogram>
<histogram
+ name="Extensions.ContentSettings.PrimaryPatternChromeExtensionScheme"
+ enum="ContentType" expires_after="2025-02-28">
+ <owner>estark@chromium.org</owner>
+ <owner>extensions-core@chromium.org</owner>
+ <summary>
+ An entry is emitted each time an extension sets a content setting whose
+ primary pattern has a Chrome extension scheme. This will be used to
+ determine if the ability to set content settings for Chrome extension
+ origins can be deprecated.
+
+ This happens on profile startup (for stored settings) and each time an
+ extension calls chrome.contentSettings[type].set(...).
+ </summary>
+</histogram>
+
+<histogram
name="Extensions.ContentSettings.PrimaryPatternUniqueSecondaryPatternDifferent"
- enum="ContentType" expires_after="2024-12-24">
+ enum="ContentType" expires_after="2025-02-28">
<owner>erikchen@chromium.org</owner>
<owner>extensions-core@chromium.org</owner>
<summary>
@@ -454,7 +470,7 @@
<histogram
name="Extensions.ContentSettings.PrimaryPatternWildcardSecondaryPatternUnique"
- enum="ContentType" expires_after="2024-12-08">
+ enum="ContentType" expires_after="2025-02-28">
<owner>erikchen@chromium.org</owner>
<owner>extensions-core@chromium.org</owner>
<summary>
@@ -468,7 +484,7 @@
<histogram
name="Extensions.ContentSettings.PrimaryPatternWildcardSecondaryPatternWildcard"
- enum="ContentType" expires_after="2025-01-26">
+ enum="ContentType" expires_after="2025-02-28">
<owner>erikchen@chromium.org</owner>
<owner>extensions-core@chromium.org</owner>
<summary>
@@ -480,6 +496,22 @@
</summary>
</histogram>
+<histogram
+ name="Extensions.ContentSettings.SecondaryPatternChromeExtensionScheme"
+ enum="ContentType" expires_after="2025-02-28">
+ <owner>estark@chromium.org</owner>
+ <owner>extensions-core@chromium.org</owner>
+ <summary>
+ An entry is emitted each time an extension sets a content setting whose
Regression Test / PoC
diff --git a/extensions/browser/api/content_settings/content_settings_store_unittest.cc b/extensions/browser/api/content_settings/content_settings_store_unittest.cc
index d064d6c..117be00 100644
--- a/extensions/browser/api/content_settings/content_settings_store_unittest.cc
+++ b/extensions/browser/api/content_settings/content_settings_store_unittest.cc
@@ -8,10 +8,12 @@
#include <memory>
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
+#include "components/content_settings/core/browser/content_settings_uma_util.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_utils.h"
@@ -349,6 +351,39 @@
store()->RemoveObserver(&observer);
}
+TEST_F(ContentSettingsStoreTest, ChromeExtensionSchemeMetrics) {
+ base::HistogramTester histogram_tester;
+ content_settings::ContentSettingsRegistry::GetInstance();
+ std::string extension_id(32, 'a');
+ ContentSettingsPattern chrome_extension_pattern =
+ ContentSettingsPattern::FromString(
+ "chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/");
+ ContentSettingsPattern https_pattern =
+ ContentSettingsPattern::FromString("https://example.test/");
+
+ RegisterExtension(extension_id);
+ store()->SetExtensionContentSetting(
+ extension_id, chrome_extension_pattern, https_pattern,
+ ContentSettingsType::COOKIES, CONTENT_SETTING_ALLOW,
+ ChromeSettingScope::kRegular);
+ histogram_tester.ExpectUniqueSample(
+ "Extensions.ContentSettings.PrimaryPatternChromeExtensionScheme",
+ content_settings_uma_util::ContentSettingTypeToHistogramValue(
+ ContentSettingsType::COOKIES),
+ 1);
+
+ RegisterExtension(extension_id);
+ store()->SetExtensionContentSetting(
+ extension_id, https_pattern, chrome_extension_pattern,
+ ContentSettingsType::IMAGES, CONTENT_SETTING_ALLOW,
+ ChromeSettingScope::kRegular);
+ histogram_tester.ExpectUniqueSample(
+ "Extensions.ContentSettings.SecondaryPatternChromeExtensionScheme",
+ content_settings_uma_util::ContentSettingTypeToHistogramValue(
+ ContentSettingsType::IMAGES),
+ 1);
+}
+
TEST_F(ContentSettingsStoreTest, SetExtensionContentSettingFromList) {
content_settings::ContentSettingsRegistry::GetInstance();
diff --git a/extensions/test/DEPS b/extensions/test/DEPS
index d70103cd..0b22280d 100644
--- a/extensions/test/DEPS
+++ b/extensions/test/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/content_settings/core/common",
"+content/public",
"+ui/aura/test",
"+ui/gl",
diff --git a/extensions/test/extensions_unittests_main.cc b/extensions/test/extensions_unittests_main.cc
index d9e86fa1..ce77637d 100644
--- a/extensions/test/extensions_unittests_main.cc
+++ b/extensions/test/extensions_unittests_main.cc
@@ -10,6 +10,7 @@
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_io_thread.h"
#include "build/buildflag.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
#include "content/public/common/content_client.h"
#include "content/public/test/content_test_suite_base.h"
#include "content/public/test/unittest_test_suite.h"
@@ -22,6 +23,9 @@
namespace {
+const char* const kNonWildcardDomainNonPortSchemes[] = {
+ extensions::kExtensionScheme};
+
// Content client that exists only to register chrome-extension:// scheme with
// the url module.
// TODO(jamescook): Should this be merged with ShellContentClient? Should this
@@ -69,6 +73,9 @@
{
ExtensionsContentClient content_client;
RegisterContentSchemes(&content_client);
+ ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(
+ kNonWildcardDomainNonPortSchemes,
+ std::size(kNonWildcardDomainNonPortSchemes));
}
RegisterInProcessThreads();
Original Bug Report
Security: Chrome extension able to grant itself content setting permissions due to faulty pattern matching
A chrome extension, with the help of permissions - contentSettings and activeTab, can grant itself access to all the features like geolocation data, microphone, camera etc. without exclusively asking it from the End User.
VULNERABILITY DETAILS
Normally (as per the codebase https://chromium.googlesource.com/chromium/chromium/+/master/chrome/common/content_settings_pattern.cc#288 ), allowed patterns are:
- [*.]domain.tld (matches domain.tld and all sub-domains)
- host (matches an exact hostname)
- a.b.c.d (matches an exact IPv4 ip)
- [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
- file:///tmp/test.html (a complete URL without a host)
However, the pattern “*://chrome-extension-ID/*” can also be passed as primaryPattern and any contentSetting can be set to allow.
This will be enable the chrome extension calling the method:
chrome.contentSettings.microphone.set({
primaryPattern: ‘*://chrome-extension-ID/*’,
setting: ‘allow’
}, function(){});
to gain access to the microphone and act as a spyware.
VERSION
Chrome Version: Tested on v53.0.2785.116 and above [stable]
Operating System: Ubuntu 16.04 (64-bit), Windows 8, Windows 10 (will exist for Mac as well)