Chrome · Media
CVE-2026-113107
UAF in Media
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fchrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc |
modified | |
ifchrome/browser/media/BUILD.gn |
modified |
Files Changed
chrome/browser/media/BUILD.gnchrome/browser/media/android/cdm/media_drm_storage_factory.ccchrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc
Patch
From 83523e3cf61d7b11285a38b4fabbd70e4019a101 Mon Sep 17 00:00:00 2001 From: Vikram Pasupathy <[email protected]> Date: Mon, 21 Sep 2026 16:25:59 -0700 Subject: [PATCH] Disallow MediaDrmStorage creation for off-the-record profiles On Android, persistent MediaDrm state is withheld in Incognito via renderer-side key-system filtering, but CreateMediaDrmStorage() did not verify whether the requesting RenderFrameHost belongs to an off-the-record profile. Because media.media_drm_storage is not in the Incognito pref allowlist, binding MediaDrmStorageImpl against an OTR PrefService allowed pref reads to fall through to the regular profile's store. Gate CreateMediaDrmStorage() on !profile->IsOffTheRecord() so the receiver is dropped and CDM creation fails closed in Incognito. This will not affect behavior, as incognito on Android Chrome already does not allow playback. Code reference here: https://source.chromium.org/chromium/chromium/src/+/main:components/cdm/renderer/key_system_support_update.cc;l=307-313 Bug: 559776445 Change-Id: I7385cd2d74b4f870607c318e09ef1931641dc449 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8421816 Commit-Queue: Vikram Pasupathy <[email protected]> Reviewed-by: Frank Liberato <[email protected]> Cr-Commit-Position: refs/heads/main@{#1702184} --- diff --git a/chrome/browser/media/android/cdm/media_drm_storage_factory.cc b/chrome/browser/media/android/cdm/media_drm_storage_factory.cc index ab42a8d..c3e5411 100644 --- a/chrome/browser/media/android/cdm/media_drm_storage_factory.cc +++ b/chrome/browser/media/android/cdm/media_drm_storage_factory.cc @@ -108,6 +108,10 @@ Profile* profile = Profile::FromBrowserContext(browser_context); DCHECK(profile) << "Profile not available."; + if (profile->IsOffTheRecord()) { + DVLOG(1) << __func__ << ": MediaDrm storage not available off the record."; + return; + } PrefService* pref_service = profile->GetPrefs(); DCHECK(pref_service) << "PrefService not available."; diff --git a/chrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc b/chrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc new file mode 100644 index 0000000..1c8875a --- /dev/null +++ b/chrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc @@ -0,0 +1,42 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media/android/cdm/media_drm_storage_factory.h" + +#include <memory> + +#include "chrome/browser/profiles/profile.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/navigation_simulator.h" +#include "content/public/test/web_contents_tester.h" +#include "media/mojo/mojom/media_drm_storage.mojom.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +using MediaDrmStorageFactoryTest = ChromeRenderViewHostTestHarness; + +TEST_F(MediaDrmStorageFactoryTest, RejectsOffTheRecordProfile) { + const GURL kTestOrigin("https://example.com"); + content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), + kTestOrigin); + mojo::Remote<media::mojom::MediaDrmStorage> regular_storage; + CreateMediaDrmStorage(main_rfh(), + regular_storage.BindNewPipeAndPassReceiver()); + regular_storage.FlushForTesting(); + EXPECT_TRUE(regular_storage.is_connected()); + + Profile* otr_profile = + profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true); + std::unique_ptr<content::WebContents> otr_web_contents = + content::WebContentsTester::CreateTestWebContents(otr_profile, nullptr); + content::NavigationSimulator::NavigateAndCommitFromBrowser( + otr_web_contents.get(), kTestOrigin); + mojo::Remote<media::mojom::MediaDrmStorage> otr_storage; + CreateMediaDrmStorage(otr_web_contents->GetPrimaryMainFrame(), + otr_storage.BindNewPipeAndPassReceiver()); + otr_storage.FlushForTesting(); + EXPECT_FALSE(otr_storage.is_connected()); +} diff --git a/chrome/browser/media/BUILD.gn b/chrome/browser/media/BUILD.gn index 1390d0cb..5f98a5e 100644 --- a/chrome/browser/media/BUILD.gn +++ b/chrome/browser/media/BUILD.gn @@ -148,13 +148,18 @@ } if (is_android) { - sources += [ "android/cdm/media_drm_origin_id_manager_unittest.cc" ] + sources += [ + "android/cdm/media_drm_origin_id_manager_unittest.cc", + "android/cdm/media_drm_storage_factory_unittest.cc", + ] deps += [ ":impl", "//base/test:test_support", "//chrome/test:test_support", "//components/prefs:test_support", "//content/test:test_support", + "//media/mojo/mojom", + "//mojo/public/cpp/bindings", ] }
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc b/chrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc
new file mode 100644
index 0000000..1c8875a
--- /dev/null
+++ b/chrome/browser/media/android/cdm/media_drm_storage_factory_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright 2026 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/android/cdm/media_drm_storage_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/web_contents_tester.h"
+#include "media/mojo/mojom/media_drm_storage.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using MediaDrmStorageFactoryTest = ChromeRenderViewHostTestHarness;
+
+TEST_F(MediaDrmStorageFactoryTest, RejectsOffTheRecordProfile) {
+ const GURL kTestOrigin("https://example.com");
+ content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
+ kTestOrigin);
+ mojo::Remote<media::mojom::MediaDrmStorage> regular_storage;
+ CreateMediaDrmStorage(main_rfh(),
+ regular_storage.BindNewPipeAndPassReceiver());
+ regular_storage.FlushForTesting();
+ EXPECT_TRUE(regular_storage.is_connected());
+
+ Profile* otr_profile =
+ profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true);
+ std::unique_ptr<content::WebContents> otr_web_contents =
+ content::WebContentsTester::CreateTestWebContents(otr_profile, nullptr);
+ content::NavigationSimulator::NavigateAndCommitFromBrowser(
+ otr_web_contents.get(), kTestOrigin);
+ mojo::Remote<media::mojom::MediaDrmStorage> otr_storage;
+ CreateMediaDrmStorage(otr_web_contents->GetPrimaryMainFrame(),
+ otr_storage.BindNewPipeAndPassReceiver());
+ otr_storage.FlushForTesting();
+ EXPECT_FALSE(otr_storage.is_connected());
+}
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