← WebKit Silent-Fix Report — 2026-W23

841ad59485b9991f47dd40dc1c9652bc714f7231  WebKit NetworkProcess: CORS bypass via unvalidated SetCORSDisablingPatterns IPC

severity high class CrossOrigin confidence 0.90 NetworkProcess IPC exploitable-grade
Chris Dumez Fri Jun 5 09:55:00 2026 -0700 full: 841ad59485b9991f47dd40dc1c9652bc714f7231 bug report ↗ view on GitHub ↗
Primitive: CORS bypass via unvalidated SetCORSDisablingPatterns IPC from web process
Triage note: Removes the NetworkConnectionToWebProcess::setCORSDisablingPatterns IPC handler and its .messages.in entry, instead applying patterns only from trusted UIProcess-supplied parameters at connection creation; previously a compromised web process could send arbitrary CORS-disabling patterns to the network process and defeat same-origin enforcement.
Contents

The bug at a glance

The vulnerable IPC is exposed to the WebContent process, which is the standard post-renderer-compromise attacker position in WebKit’s threat model, so this is a second-stage sandbox-escape-adjacent capability rather than a pure remote bug. A compromised WebContent process could send SetCORSDisablingPatterns with a pattern like *://*/* to the NetworkProcess and defeat same-origin enforcement, letting it read the body of any cross-origin site the user is authenticated to (SOP/CORS bypass, confidentiality-critical). High/8.1 reflects the requirement of an already-compromised renderer combined with the severe cross-origin data-theft impact and no user interaction beyond browsing.

CORS-disabling patterns are a legitimate embedder feature (_corsDisablingPatterns SPI, WebExtensions), but the plumbing let the NetworkProcess accept those patterns from the WebContent process over Messages::NetworkConnectionToWebProcess::SetCORSDisablingPatterns. That put an untrusted, potentially-compromised renderer directly in the trust path for a decision — “disable the same-origin policy for these URLs” — that only the trusted UIProcess is entitled to make. A compromised renderer could simply send the message with *://*/* and turn the NetworkProcess into an open cross-origin proxy for the user’s authenticated sessions. The fix deletes the WebContent-process IPC entirely and re-routes the patterns from the UIProcess straight to the NetworkProcess, with a fallback that ships them inside the connection-creation parameters when the NetworkProcess isn’t up yet.

Root cause

The vulnerable state is the network-side enforcement data consulted by NetworkProcess::shouldDisableCORSForRequestTo: the per-page CORS-disabling patterns and the per-connection originAccessPatterns(). Before the patch, that state could be written by the WebContent process. NetworkConnectionToWebProcess::setCORSDisablingPatterns(PageIdentifier, Vector<String>&&) was an IPC handler (declared in NetworkConnectionToWebProcess.messages.in as SetCORSDisablingPatterns(WebCore::PageIdentifier pageIdentifier, Vector<String> patterns)) that forwarded straight to m_networkProcess->setCORSDisablingPatterns(*this, pageIdentifier, ...).

The reaching path from an attacker: a compromised WebContent process crafts and sends Messages::NetworkConnectionToWebProcess::SetCORSDisablingPatterns(pageID, {"*://*/*"}) on its existing NetworkProcessConnection. The handler parsed each string as a UserContentURLPattern and, for valid patterns, called connection.originAccessPatterns().allowAccessTo(parsedPattern) and stored them for the page — so subsequent cross-origin fetches from that renderer would pass shouldDisableCORSForRequestTo for arbitrary origins. Nothing validated that the renderer was actually entitled to those patterns; the values were entirely attacker-chosen.

This is unsafe because in WebKit’s process model the WebContent process is untrusted (it runs web content and is the assumed-compromised party), whereas CORS-disabling is a privileged embedder configuration that originates in the UIProcess as _corsDisablingPatterns. Legitimately the flow was UIProcess -> WebContent -> NetworkProcess, and WebPage::synchronizeCORSDisablingPatternsWithNetworkProcess() sent the IPC on the renderer’s behalf; but because the message crossed a trust boundary through the untrusted middle hop, a compromised renderer could substitute any patterns it wanted. The result is a full same-origin-policy / CORS bypass usable to exfiltrate authenticated cross-origin content.

The fix removes the WebContent process from the trust path. It deletes the SetCORSDisablingPatterns message and handler (and the header decl), deletes WebPage::synchronizeCORSDisablingPatternsWithNetworkProcess() and its callers in WebPage’s constructor/destructor/updateCORSDisablingPatterns and in WebProcess::ensureNetworkProcessConnection. In their place, the UIProcess sends patterns directly: WebPageProxy::setCORSDisablingPatterns and the new sendCORSDisablingPatternsToNetworkProcessIfNecessary() send Messages::NetworkProcess::SetCORSDisablingPatternsForPage(processIdentifier, pageID, patterns) straight to the trusted NetworkProcess, finishAttachingToWebProcess replays them across process swaps, and for the not-yet-launched case the patterns ride along in NetworkProcessConnectionParameters::corsDisablingPatternsPerPage, applied in NetworkProcess::createNetworkConnectionToWebProcess. The renderer still receives Messages::WebPage::UpdateCORSDisablingPatterns only to populate its own WebCore-side OriginAccessPatternsForWebProcess singleton, which governs same-process checks and is not authoritative for the NetworkProcess.

Key code

Removed renderer-facing message/handler and the new UIProcess-direct enforcement path

// NetworkConnectionToWebProcess.messages.in (DELETED — renderer could send this):
-   SetCORSDisablingPatterns(WebCore::PageIdentifier pageIdentifier, Vector<String> patterns)

// NetworkConnectionToWebProcess.cpp (DELETED handler):
-void NetworkConnectionToWebProcess::setCORSDisablingPatterns(PageIdentifier pageIdentifier, Vector<String>&& patterns)
-{ m_networkProcess->setCORSDisablingPatterns(*this, pageIdentifier, WTF::move(patterns)); }

// NetworkProcess.cpp (new UIProcess-facing message target):
void NetworkProcess::setCORSDisablingPatternsForPage(WebCore::ProcessIdentifier webProcessIdentifier, PageIdentifier pageIdentifier, Vector<String>&& patterns)
{
    auto parsedPatterns = WTF::compactMap(WTF::move(patterns), [&](auto&& pattern) -> std::optional<UserContentURLPattern> {
        UserContentURLPattern parsedPattern(WTF::move(pattern));
        if (!parsedPattern.isValid())
            return std::nullopt;
        if (RefPtr connection = webProcessConnection(webProcessIdentifier))
            connection->originAccessPatterns().allowAccessTo(parsedPattern);
        return parsedPattern;
    });
    ...
}

// WebPageProxy.cpp (UIProcess sends directly to NetworkProcess):
void WebPageProxy::sendCORSDisablingPatternsToNetworkProcessIfNecessary()
{
    if (m_corsDisablingPatterns.isEmpty()) return;
    RefPtr networkProcess = websiteDataStore().networkProcessIfExists();
    if (!networkProcess) return;
    networkProcess->send(Messages::NetworkProcess::SetCORSDisablingPatternsForPage(
        legacyMainFrameProcess().coreProcessIdentifier(), webPageIDInMainFrameProcess(), m_corsDisablingPatterns), 0);
}

Patch walkthrough

  • Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp / .h / .messages.in — Deletes the setCORSDisablingPatterns handler, its private declaration, and the SetCORSDisablingPatterns(WebCore::PageIdentifier, Vector<String>) entry in the WebContent-facing .messages.in. This removes the untrusted renderer’s ability to push CORS-disabling patterns to the NetworkProcess at all — the core of the fix, closing the attack surface.
  • Source/WebKit/NetworkProcess/NetworkProcess.cpp / .h / .messages.in — Renames setCORSDisablingPatterns(NetworkConnectionToWebProcess&, ...) to setCORSDisablingPatternsForPage(WebCore::ProcessIdentifier, PageIdentifier, Vector<String>&&) and exposes it as a new UIProcess-facing message SetCORSDisablingPatternsForPage. The reworked body looks up the connection via webProcessConnection(webProcessIdentifier) (rather than trusting a caller-supplied connection) to populate originAccessPatterns(), with a comment stating a compromised WebContent process must not be able to disable CORS. createNetworkConnectionToWebProcess now applies parameters.corsDisablingPatternsPerPage at connection-creation time.
  • Source/WebKit/Shared/NetworkProcessConnectionParameters.h / .serialization.in — Adds HashMap<WebCore::PageIdentifier, Vector<String>> corsDisablingPatternsPerPage to the connection parameters (and its serialization entry), plus the needed PageIdentifier/HashMap includes. This is the trusted channel for delivering patterns when the NetworkProcess has not yet been launched, so no renderer IPC is needed to bootstrap them.
  • Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp — In getNetworkProcessConnection, for each main page with non-empty corsDisablingPatterns(), populates parameters.corsDisablingPatternsPerPage keyed by webPageIDInMainFrameProcess(). This wires the UIProcess’s authoritative pattern list into the connection-creation parameters.
  • Source/WebKit/UIProcess/WebPageProxy.cpp / .hsetCORSDisablingPatterns now also calls the new sendCORSDisablingPatternsToNetworkProcessIfNecessary(), which (if patterns are non-empty and a NetworkProcess exists) sends Messages::NetworkProcess::SetCORSDisablingPatternsForPage(legacyMainFrameProcess().coreProcessIdentifier(), webPageIDInMainFrameProcess(), m_corsDisablingPatterns) directly to the NetworkProcess. finishAttachingToWebProcess calls the same helper so patterns are replayed after a process swap.
  • Source/WebKit/WebProcess/WebPage/WebPage.cpp / .h and WebProcess.cpp — Deletes WebPage::synchronizeCORSDisablingPatternsWithNetworkProcess() and every call to it: in the WebPage constructor, the destructor’s clear-on-teardown path, and updateCORSDisablingPatterns; also removes the RunLoop dispatch in WebProcess::ensureNetworkProcessConnection that resynchronized all pages’ patterns on connection setup. The WebContent process retains only page->setCORSDisablingPatterns(parseAndAllowAccessToCORSDisablingPatterns(...)) for its own in-process WebCore same-origin checks.

Background

WebKit process trust model — The WebContent (renderer) process is treated as untrusted and assumed compromisable by web content; the UIProcess is the trusted arbiter of security policy; the NetworkProcess performs network I/O and enforces CORS/SOP. Privileged configuration must flow UIProcess -> NetworkProcess without depending on a renderer, which this patch enforces.

CORS-disabling patterns / _corsDisablingPatterns — An embedder SPI (also used by WebExtensions) that whitelists URL patterns for which the same-origin policy is relaxed, letting an app fetch cross-origin resources. UserContentURLPattern parses entries like *://*/*; the NetworkProcess consults them in shouldDisableCORSForRequestTo. Because relaxing SOP is a powerful capability, its source must be trusted.

originAccessPatterns() / OriginAccessPatternsForWebProcess — The NetworkProcess keeps per-connection originAccessPatterns() used when deciding whether to disable CORS for a request. Separately, the WebContent process keeps its own OriginAccessPatternsForWebProcess singleton for WebCore-side same-origin checks; the patch still populates the latter via UpdateCORSDisablingPatterns but no longer lets it drive the NetworkProcess’s authoritative copy.

NetworkProcessConnectionParameters — A struct serialized when a WebProcess’s NetworkProcess connection is created. Adding corsDisablingPatternsPerPage lets the UIProcess-supplied patterns be applied at createNetworkConnectionToWebProcess time, closing the bootstrap gap where the NetworkProcess isn’t yet running to receive a direct message.

Vulnerability window

  1. Legitimate design — Embedder sets _corsDisablingPatterns in UIProcess; patterns propagated UIProcess -> WebContent -> NetworkProcess via WebPage::synchronizeCORSDisablingPatternsWithNetworkProcess() sending NetworkConnectionToWebProcess::SetCORSDisablingPatterns.
  2. Renderer compromise — An attacker exploits a separate renderer bug to run code in the WebContent process, gaining the ability to send arbitrary IPC on the existing NetworkProcessConnection.
  3. Abuse the IPC — The compromised renderer sends SetCORSDisablingPatterns(pageID, {"*://*/*"}); the NetworkProcess handler accepts it, calls allowAccessTo, and stores the patterns for the page.
  4. Cross-origin exfiltration — Subsequent fetches pass shouldDisableCORSForRequestTo for arbitrary origins, so the renderer reads responses from any cross-origin site the user is authenticated to.
  5. Fix — The renderer-facing message and sync code are deleted; patterns flow UIProcess -> NetworkProcess directly (via SetCORSDisablingPatternsForPage and connection parameters), replayed across process swaps in finishAttachingToWebProcess.

Triggering

No PoC is reconstructable from the patch: there is no regression test in the diff, and triggering the bug requires an already-compromised WebContent process able to synthesize the Messages::NetworkConnectionToWebProcess::SetCORSDisablingPatterns(pageID, {"*://*/*"}) IPC on its NetworkProcessConnection — a native second-stage capability, not a scriptable web primitive. Conceptually, a compromised renderer sends that message and then issues cross-origin fetches that the NetworkProcess no longer subjects to CORS; but fabricating the renderer-compromise primitive is out of scope of this patch and no such primitive is provided.

Exploitation

  1. Obtain renderer code execution — Chain a separate WebContent-process vulnerability to run attacker-controlled native code inside the sandboxed renderer, which holds a live NetworkProcessConnection.
  2. Push permissive patterns — Send SetCORSDisablingPatterns with a broad pattern (e.g. *://*/*) for the page identifier, causing the NetworkProcess to relax CORS for all origins on that page’s connection.
  3. Steal authenticated cross-origin data — Issue cross-origin requests to sites where the user has cookies/credentials and read the responses that CORS would normally block, exfiltrating private data. This is a confidentiality breach, not memory corruption.

Detection & hunting

For defenders and SOC / detection engineers:

  • Renderer-originated CORS-policy IPC
  • Unexpected origin-access relaxation
  • Cross-origin reads post-renderer-anomaly

Audit directions

  • Other NetworkConnectionToWebProcess.messages.in handlers
  • UIProcess-supplied identifiers
  • Process-swap and cold-start replay

Before / after

Loading diff…