← WebKit Silent-Fix Report — 2026-W25

f10b871ab9  Gate InstallMockContentFilter IPC behind AllowTestOnlyIPC

severity medium class Bypass confidence 0.60 WebKit Network IPC exploitable-grade
Darryl Parkinson Mon Jun 15 16:10:08 2026 -0700 full: f10b871ab9020a41d4e398647cfe587045ec8097 bug report ↗ view on GitHub ↗
Primitive: ungated test-only IPC installs mock content filter
Triage note: Test-only IPC to install a mock content filter was reachable in production; gating it prevents a content-filtering bypass.
Contents

The bug at a glance

A test-only IPC message, InstallMockContentFilter on NetworkConnectionToWebProcess, was reachable in production builds and overwrote a process-global MockContentFilterSettings singleton in the NetworkProcess. A compromised WebContent process could thereby install a mock content filter that redirects or blocks navigations for every connection served by that NetworkProcess – a cross-process, cross-tab navigation-integrity bypass. It is medium because it requires an already-compromised/IPC-capable WebContent process as a precondition and yields navigation redirection/blocking rather than direct memory corruption.

This is a classic ‘debug hook shipped to production’ attack-surface bug. The dangerous property is that InstallMockContentFilter mutates a NetworkProcess-global singleton, so one malicious renderer’s message affects navigations for all connections, not just its own. The fix gates it behind a dedicated EnabledBy=AllowTestOnlyMockContentFilterIPC preference that defaults false everywhere except the test runner.

Root cause

OBSERVED: In NetworkConnectionToWebProcess.messages.in the message was declared unconditionally (under #if ENABLE(CONTENT_FILTERING)) as InstallMockContentFilter(WebCore::MockContentFilterSettings settings). Any process holding a NetworkConnectionToWebProcess connection could send it.

OBSERVED (commit message): the handler ‘overwrites a process-global MockContentFilterSettings singleton, allowing a compromised WebContent process to redirect or block navigations for all connections in the NetworkProcess.’ Because the settings are process-global, the effect is not scoped to the sending connection.

OBSERVED: the message is ‘only used by test infrastructure to configure mock content filtering.’ The added regression test demonstrates the primitive: webViewA (attacker) sends the IPC via the IPC testing API with a mock filter configured to redirect to http://…/evil with decision=block/redirect, then webViewB navigates to an unrelated victim origin; the mock filter installed by A causes B’s navigation body to become ‘REDIRECTED’ instead of ‘ORIGINAL’.

OBSERVED: the fix adds a new shared-for-web-process preference AllowTestOnlyMockContentFilterIPC (default false) and annotates the message [EnabledBy=AllowTestOnlyMockContentFilterIPC], so the IPC is rejected unless that test-only flag is set. INFERRED: with the gate, production WebContent processes (which do not set the flag) can no longer install a mock filter, closing the cross-connection navigation-tampering path.

Key code

The gate on the message declaration (verbatim, NetworkConnectionToWebProcess.messages.in)

#if ENABLE(CONTENT_FILTERING)
    [EnabledBy=AllowTestOnlyMockContentFilterIPC] InstallMockContentFilter(WebCore::MockContentFilterSettings settings)
#endif

Patch walkthrough

  • Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml — Declares a new embedder preference AllowTestOnlyMockContentFilterIPC (type bool, defaultValue false, sharedPreferenceForWebProcess: true), modeled on the existing AllowTestOnlyIPC/AllowTestOnlyOriginAccessAllowListIPC flags. This is the off-by-default gate.
  • Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in — Prefixes the InstallMockContentFilter message with [EnabledBy=AllowTestOnlyMockContentFilterIPC], so the IPC dispatch machinery rejects the message unless the receiving side has the flag enabled. This is the core security change.
  • Tools/TestWebKitAPI/Tests/WebKit/WKWebView/ContentFiltering.mm — Updates configurationWithContentFilterSettings() to enable the AllowTestOnlyMockContentFilterIPC feature via WKPreferences so existing content-filtering API tests keep working under the new gate.
  • Tools/TestWebKitAPI/Tests/WebKit/WKWebView/IPCTestingAPI.mm — Adds InstallMockContentFilterRequiresTestOnlyIPC and InstallMockContentFilterRedirectsWithTestOnlyIPC. The helper sends the InstallMockContentFilter IPC from web view A, then navigates web view B (sharing the process pool / NetworkProcess) and checks whether B’s navigation was redirected – asserting no effect when the flag is off (ORIGINAL) and redirection when on (REDIRECTED).
  • Tools/WebKitTestRunner/TestController.cpp / TestOptions.cpp / TestOptions.h — Wires the new flag into WebKitTestRunner: default true for layout tests, a keyTypeMapping entry, an accessor allowTestOnlyMockContentFilterIPC(), and pushing it into preferences in resetPreferencesToConsistentValues so existing content-filter tests remain functional.

Background

NetworkConnectionToWebProcess — The NetworkProcess-side endpoint of the IPC connection to a single WebContent process. Messages declared in its .messages.in file are handlers the NetworkProcess exposes to that renderer. Because the NetworkProcess is shared across many WebContent connections, a handler that mutates global state affects all of them.

MockContentFilterSettings singleton — A process-global configuration object used by the mock content-filter test harness to simulate parental-controls / enterprise content filtering, including forcing a navigation to be blocked or redirected. Being process-global, an install performed for one connection changes filtering behavior for navigations on other connections in the same NetworkProcess.

EnabledBy / test-only IPC gating — WebKit’s message-generation supports annotating a message with [EnabledBy=SomePreference] so the dispatcher drops the message unless that preference is enabled on the receiving side. The AllowTestOnlyIPC family (and now AllowTestOnlyMockContentFilterIPC) are off-by-default preferences used to fence off IPC that exists purely for testing.

Compromised-WebContent threat model — WebKit’s sandbox architecture assumes a renderer may be fully compromised via a content bug; the NetworkProcess must remain robust against malicious IPC from it. An ungated test message that lets a renderer alter global navigation filtering violates that boundary even without memory corruption.

IPCTestingAPI — A test-only JS-reachable interface (IPC.sendMessage) that lets a page send raw IPC messages, used here to prove the attack: it sends NetworkConnectionToWebProcess_InstallMockContentFilter with attacker-chosen redirect settings.

Vulnerability window

  1. Exposure — InstallMockContentFilter is declared as an ungated message on NetworkConnectionToWebProcess, reachable from any WebContent process where content filtering is enabled.
  2. Weakness — Handling it overwrites the process-global MockContentFilterSettings, so a single renderer can redirect/block navigations across all connections in the NetworkProcess.
  3. Original fix — Landed first on a Safari branch (305413.453@rapid/safari-7624.2.5.110-branch, rdar://176065359) gating the message behind the new preference.
  4. Upstream landing — Merged to main as 315249@main (bug 309091 / rdar://171645964), adding AllowTestOnlyMockContentFilterIPC and the [EnabledBy=…] annotation plus regression tests.
  5. Verification — New IPCTestingAPI tests assert the IPC is inert with the flag off and redirects with it on.

Proof of concept

Verbatim excerpt of the added IPCTestingAPI test (trimmed only where noted with ‘…’). It demonstrates the primitive: attacker web view A installs a mock content filter that redirects to /evil; victim web view B, served by the same NetworkProcess, then navigates to /victim and its body becomes ‘REDIRECTED’. With the gate off (false) the navigation is unaffected (‘ORIGINAL’); with it on (true) the redirect fires, proving both the vulnerability and the fix.

static NSString *installMockContentFilterAndNavigateVictim(bool allowMockContentFilterIPC)
{
    using namespace TestWebKitAPI;

    HTTPServer attackerServer({
        { "/attacker"_s, { "<!DOCTYPE html>"_s } },
        { "/evil"_s, { "<!DOCTYPE html><body>REDIRECTED</body>"_s } },
    });
    HTTPServer victimServer({
        { "/victim"_s, { "<!DOCTYPE html><body>ORIGINAL</body>"_s } },
    });
    // ... webViewA sends InstallMockContentFilter via IPC.sendMessage ...
    [webViewA stringByEvaluatingJavaScript:[NSString stringWithFormat:
        @"IPC.sendMessage('Networking', 0,"
        "  IPC.messages.NetworkConnectionToWebProcess_InstallMockContentFilter.name,"
        "  [ { type: 'bool', value: 1 }, ... ,"
        "    { type: 'String', value: 'http://127.0.0.1:%u/evil' }, ... ]"
        ")", attackerServer.port()]];
    // webViewB (same process pool) then navigates to /victim
    return bodyText; // "REDIRECTED" if the mock filter took effect
}

TEST(IPCTestingAPI, InstallMockContentFilterRequiresTestOnlyIPC)
{
    EXPECT_WK_STREQ(installMockContentFilterAndNavigateVictim(false), "ORIGINAL");
}

TEST(IPCTestingAPI, InstallMockContentFilterRedirectsWithTestOnlyIPC)
{
    EXPECT_WK_STREQ(installMockContentFilterAndNavigateVictim(true), "REDIRECTED");
}

Exploitation

  1. Precondition — Attacker needs a WebContent process able to send the IPC – in the wild, a renderer compromised via a separate content bug (the test uses the special IPCTestingAPI to stand in for that capability).
  2. Action — Send InstallMockContentFilter with settings that force navigations to be blocked or redirected to an attacker URL, overwriting the NetworkProcess-global mock filter singleton.
  3. Impact — All subsequent navigations across every connection in that NetworkProcess can be redirected/blocked, enabling cross-origin navigation tampering / phishing-style redirection and denial of navigation. This is an integrity bypass, not memory corruption; no code-execution primitive is implied by the patch.
  4. Honest limits — Requires the compromised-renderer precondition; effect is bounded by what the mock content-filter mechanism can express (block/redirect). Post-fix, production renderers cannot enable the flag.

Detection & hunting

For defenders and SOC / detection engineers:

  • Unexpected InstallMockContentFilter IPC
  • Navigation-integrity anomalies
  • Ungated test IPC audit

Audit directions

  • Other test-only IPCs
  • Process-global mutable singletons
  • Content-filtering path integrity

Before / after

Loading diff…