← WebKit — 2026-W41

b2fb1f240e251d103130fbba79ad202fbae0f6b4  Give extension page subframes unpartitioned storage access

severity medium class AuthorizationError confidence 0.4 signal score 12.42 Source/WebCore/dom
Primitive: Storage keying for frames with unpartitioned storage access, with IPC validation that a web process only claims storage client origins it committed
Triage note: Adds storageTopOrigin()/storageClientOrigin() (securityOrigin when hasUnpartitionedStorageAccess, else topOrigin) threaded through IDB/caches/web-locks/service-worker/storage code, plus a new ProcessCommittedStorageClientOrigin IPC validation (Terminate on mismatch) gating WebLockRegistryProxy and m_committedStorageClientOrigins populated only when a subframe's unpartitionedStorageSite matches. Mostly Storage Access API feature plumbing, but includes a genuine untrusted-origin IPC access control; no standalone pre-existing vuln clearly fixed.
Structural signals: smartptr_member_added (+6.47), null_guard (+1.2), uaf_lifetime (+4.75), area:Source/WebCore/dom (+2.0), large_churn (-2.0)

Commit message

Give extension page subframes unpartitioned storage access
https://bugs.webkit.org/show_bug.cgi?id=326512
rdar://189301936

Reviewed by Sihui Liu.

Subframes of extension pages with unpartitioned storage access get first-party cookies, but other
storage APIs stayed partitioned. Add ScriptExecutionContext::storageTopOrigin(), which returns the
context's own origin when it has unpartitioned access, and use it for localStorage, sessionStorage,
IndexedDB, Cache Storage, OPFS, Web Locks, BroadcastChannel, StorageManager and service workers.
Blob URLs and the HTTP cache intentionally remain partitioned.

For subframe navigations, service worker matching uses the request's isTopSite() bit rather than
hasUnpartitionedStorageAccess, since the latter reflects the document being navigated away from.

Test: Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebExtensionUnpartitionedStorage.mm

* LayoutTests/ipc/scheduleresourceload-resume-bind-to-claimant-message-check.html:
* Source/WebCore/Modules/cache/DOMCacheStorage.cpp:
(WebCore::DOMCacheStorage::origin const):
* Source/WebCore/Modules/filesystem/FileSystemStorageConnection.cpp:
(WebCore::clientOriginForContext):
* Source/WebCore/Modules/indexeddb/IDBFactory.cpp:
(WebCore::IDBFactory::openInternal):
(WebCore::IDBFactory::deleteDatabase):
* Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp:
(WebCore::IDBClient::IDBConnectionProxy::getAllDatabaseNamesAndVersions):
* Source/WebCore/Modules/storage/StorageManager.cpp:
(WebCore::connectionInfo):
* Source/WebCore/Modules/web-locks/WebLockManager.cpp:
(WebCore::clientOriginFromContext):
* Source/WebCore/dom/BroadcastChannel.cpp:
(WebCore::partitionedSecurityOriginFromContext):
* Source/WebCore/dom/Document.cpp:
(WebCore::Document::updateServiceWorkerClientData):
* Source/WebCore/dom/Document.h:
(WebCore::Document::hasUnpartitionedStorageAccess const): Deleted.
* Source/WebCore/dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::storageClientOrigin const):
(WebCore::ScriptExecutionContext::canAccessResource const):
* Source/WebCore/dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::hasUnpartitionedStorageAccess const):
(WebCore::ScriptExecutionContext::storageTopOrigin const):
* Source/WebCore/loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::matchRegistration):
* Source/WebCore/storage/StorageNamespaceProvider.cpp:
(WebCore::StorageNamespaceProvider::localStorageArea):
(WebCore::StorageNamespaceProvider::sessionStorageArea):
* Source/WebCore/workers/WorkerGlobalScope.cpp:
(WebCore::WorkerGlobalScope::updateServiceWorkerClientData):
* Source/WebCore/workers/WorkerGlobalScope.h:
* Source/WebCore/workers/WorkerMessagingProxy.cpp:
(WebCore::WorkerMessagingProxy::startWorkerGlobalScope):
* Source/WebCore/workers/WorkerScriptLoader.cpp:
(WebCore::WorkerScriptLoader::loadAsynchronously):
* Source/WebCore/workers/WorkerThread.cpp:
(WebCore::WorkerParameters::isolatedCopy const):
* Source/WebCore/workers/WorkerThread.h:
* Source/WebCore/workers/service/ServiceWorkerContainer.cpp:
(WebCore::ServiceWorkerContainer::ready):
(WebCore::ServiceWorkerContainer::addRegistration):
(WebCore::ServiceWorkerContainer::updateRegistration):
(WebCore::ServiceWorkerContainer::getRegistration):
(WebCore::ServiceWorkerContainer::getRegistrations):
* Source/WebCore/workers/shared/SharedWorker.cpp:
(WebCore::SharedWorker::create):
* Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::scheduleResourceLoad):
* Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::topOriginForServiceWorkers const):
* Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.h:
* Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.serialization.in:
* Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::continueWillSendRequest):
* Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
(WebKit::WebSWServerConnection::resolveUnregistrationJobInClient):
* Source/WebKit/UIProcess/ValidationProcedures.h:
(WebKit::ProcessCommittedStorageClientOrigin::ProcessCommittedStorageClientOrigin):
(WebKit::ProcessCommittedStorageClientOrigin::checkUntrusted const):
* Source/WebKit/UIProcess/WebLockRegistryProxy.cpp:
(WebKit::WebLockRegistryProxy::requestLock):
(WebKit::WebLockRegistryProxy::releaseLock):
(WebKit::WebLockRegistryProxy::abortLockRequest):
(WebKit::WebLockRegistryProxy::snapshot):
(WebKit::WebLockRegistryProxy::clientIsGoingAway):
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didCommitLoadForFrame):
* Source/WebKit/UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::hasCommittedStorageClientOrigin const):
(WebKit::WebProcessProxy::didCommitStorageClientOrigin):
* Source/WebKit/UIProcess/WebProcessProxy.h:
* Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::scheduleLoadFromNetworkProcess):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebExtensionUnpartitionedStorage.mm:
(TestWebKitAPI::scriptReportingResult):
(TestWebKitAPI::storageTestServer):
(TestWebKitAPI::controllerConfigurationWithPersistentDataStore):
(TestWebKitAPI::loadStorageTestExtension):
(TestWebKitAPI::loadFirstPartyPage):
(TestWebKitAPI::runUnpartitionedStorageTest):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, LocalStorageIsUnpartitionedInHostPermittedFrame)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, IndexedDBIsUnpartitionedInHostPermittedFrame)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, CacheStorageIsUnpartitionedInHostPermittedFrame)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, FileSystemIsUnpartitionedInHostPermittedFrame)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, WebLocksAreUnpartitionedInHostPermittedFrame)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, DedicatedWorkerOfHostPermittedFrameIsUnpartitioned)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, SharedWorkerOfHostPermittedFrameIsUnpartitioned)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, ServiceWorkerControlsHostPermittedFrame)):
(TestWebKitAPI::copySessionStorage):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, SessionStorageIsUnpartitionedInHostPermittedFrame)):
(TestWebKitAPI::TEST(WKWebExtensionUnpartitionedStorage, BroadcastChannelIsUnpartitionedInHostPermittedFrame)):

Canonical link: https://commits.webkit.org/323034@main

Before / after

Loading diff…