[3] Connections for Private Click Measurement are not proxied
Severity: High | Component: WebKit Private Click Measurement (Network Process) | 975a11f
Rated High because the observable effect is complete user IP address disclosure on every PCM attribution report and token fetch — a direct bypass of the privacy proxy that PCM architecturally depends on — with confidence 0.93 based on the missing _sourceApplicationBundleIdentifier and cross-site classification shown in the diff, though the exact proxy-routing behavior of Apple's network stack is inferred from domain knowledge not fully verifiable from the diff alone.
PCM attribution reports and fraud prevention token fetches were not being routed through the privacy proxy because they lacked two signals required by Apple's network stack: (1) association with the application bundle (e.g., Safari), and (2) classification as third-party resource requests. The fix plumbs through the application bundle identifier or audit token and fabricates a cross-site mainDocumentURL. As a safeguard, the patch also sets _setPrivacyProxyFailClosed:YES so requests fail rather than silently falling back to direct connections when the proxy is unavailable.
Source/WebKit/NetworkProcess/PrivateClickMeasurement/cocoa/PrivateClickMeasurementNetworkLoaderCocoa.mm
- static NSURLSession *statelessSessionWithoutRedirectsSingleton()
+ static NSURLSession *statelessSessionWithoutRedirectsSingleton(const ApplicationBundleIdentifierOrAuditToken& applicationBundleIdentifier)
{
...
configuration.get()._shouldSkipPreferredClientCertificateLookup = YES;
+
+ WTF::switchOn(applicationBundleIdentifier,
+ [&] (const String& bundleIdentifier) {
+ configuration.get()._sourceApplicationBundleIdentifier = bundleIdentifier.createNSString().get();
+ }, [&] (const Vector<uint8_t>& auditToken) {
+ configuration.get()._sourceApplicationAuditTokenData = [NSData dataWithBytes:auditToken.span().data() length:auditToken.size()];
+ }
+ );
+
...
auto request = adoptNS([[NSMutableURLRequest alloc] initWithURL:url.createNSURL().get()]);
+ [request _setPrivacyProxyFailClosed:YES];
[request setValue:WebCore::HTTPHeaderValues::maxAge0().createNSString().get() forHTTPHeaderField:@"Cache-Control"];
[request setValue:WebCore::standardUserAgentWithApplicationName({ }).createNSString().get() forHTTPHeaderField:@"User-Agent"];
+ RetainPtr crossSiteMainDocument = [NSURLComponents componentsWithURL:request.get().URL resolvingAgainstBaseURL:NO];
+ crossSiteMainDocument.get().host = [NSString stringWithFormat:@"not-%@", crossSiteMainDocument.get().host];
+ [request setMainDocumentURL:crossSiteMainDocument.get().URL];
- RetainPtr task = [statelessSessionWithoutRedirectsSingleton() dataTaskWithRequest:request.get() ...];
+ RetainPtr task = [statelessSessionWithoutRedirectsSingleton(applicationBundleIdentifier) dataTaskWithRequest:request.get() ...];
Patch Details
The patch threads an ApplicationBundleIdentifierOrAuditToken (a Variant<String, Vector<uint8_t>>) from NetworkSession through PrivateClickMeasurementManager into every PCM::NetworkLoader::start() call. On the Cocoa side, statelessSessionWithoutRedirectsSingleton() now configures the NSURLSessionConfiguration with either _sourceApplicationBundleIdentifier or _sourceApplicationAuditTokenData depending on which is available. The request itself sets _setPrivacyProxyFailClosed:YES and fabricates a cross-site mainDocumentURL by prepending not- to the request host, forcing the URL loading system to classify the request as a third-party subresource. The daemon entry point (PCMDaemonEntryPoint.mm) hardcodes the Safari bundle identifier for the daemon code path.
Missing application identity and cross-site classification on privacy-sensitive network requests, causing proxy bypass.
Background
Private Click Measurement (PCM) is WebKit's privacy-preserving ad attribution system. When a user clicks an ad on a source site and later converts on a destination site, PCM sends an attribution report to the destination. To prevent tracking, these reports are designed to be sent through a privacy proxy that hides the user's IP address. PCM also fetches fraud prevention token key material from servers, which should similarly be proxied.
Apple's network stack uses two signals to decide whether to proxy a connection: the source application identity (_sourceApplicationBundleIdentifier or _sourceApplicationAuditTokenData on NSURLSessionConfiguration), which associates the request with a known app like Safari, and whether the request is a third-party (cross-site) subresource, determined by comparing the request URL's host to the mainDocumentURL's host. Both must be present for proxy routing to engage. The _setPrivacyProxyFailClosed:YES directive on NSMutableURLRequest ensures that if the proxy is unreachable, the request fails rather than falling back to a direct connection.
Analysis
Before the fix, PCM network requests were sent without either of the two signals needed for proxy routing. The NSURLSessionConfiguration lacked a source application identifier, and the requests had no mainDocumentURL to trigger cross-site classification. Without both signals, Apple's network proxy infrastructure (if the domain-knowledge understanding of its routing logic is correct) treated these as ordinary first-party requests and sent them directly. There was also no fail-closed behavior — if the proxy were unavailable, requests would silently degrade to direct connections rather than failing.
The fix is architecturally interesting in how it forces cross-site classification: it fabricates a mainDocumentURL by prepending not- to the request's own host (not-example.com for a request to example.com), guaranteeing a host mismatch that triggers third-party classification. This is a pragmatic workaround — PCM requests have no natural "first-party" document context since they originate from the Network Process, not from a page load.
Aaaa Aa Aaaaaaaa Aaaaaaaaaaa Aa a Aaaaaaa Aaaaaa a Aa Aaaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaaaaaa Aaa Aaaaaaa Aaaaaa Aaaaaaaaa Aaa Aaaaaaaaaaa Aaaaaaa Aa Aaaaaaa Aaaaa Aaaaaaaaaa Aaaaa Aaaa Aaaaa Aaaaaaa Aaa Aaaaaa Aaaa Aa Aaaaaaa Aa Aaaaa Aaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaa Aaaaaaaa Aaa Aaaaaaa Aaaaa Aaaaaaaaa Aa Aaaaaaaaaaa Aa Aaaaaaaaa Aaaa Aaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaa Aa Aaa Aaaaaaaaaaa Aaaaa Aa Aaaaaaaa Aaaaa Aaaaaaaaaaa Aaaaa Aaa Aaaaa Aaaaa Aaaaaaaaaa Aaaaaaaa Aaaaaaaa a Aaaaaaa Aaa Aaaaaaaaaaaa Aaaa Aaaaa Aaaaa Aaaaaaaaaaaa Aaa Aaaaaaaa Aa Aaaaaaaa
a Aaaaaaa Aaaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa a Aaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaaa Aaaa Aaa Aaaaa Aaaaaaaa Aaaaaa Aaaaaaaaaaa Aa Aaaaaaaa Aaaaaaa Aaaa Aaaaaaaaa Aaaaaa Aaaaaaaaaaa Aaaaa Aaaaa Aaaa Aaaa Aaaaa Aaaa Aaa Aaaaa Aaaaaaaa Aaaaaaaa Aaaaa Aa Aaaa a a Aaaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaa Aaaaaa Aa Aaaaaaaa Aaa Aaaaaaa Aaaaaaa Aaaaaaaaa Aaaaaa a Aaaaaa Aaaaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaa Aaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaa Aaaaaa Aaa Aaaa Aaa Aaa Aaaaaaa Aaaaaaa Aaaaaaa Aaa Aaaaaa Aaaa Aa Aaaaaaa Aa Aaa Aaaaaaaaaaa Aaaaaa Aaaaaaaa Aaa Aaaaa Aaaaaaaa Aaaaaaaaaaa Aaa Aaaa Aaaaaaa Aaaaaaaaa Aaaa Aaa Aa Aaaaaaaa Aa Aaaaaaaa
🔒Explores the privacy model implications and the specific network-level signals that were missing, along with the fail-closed defense-in-depth measure
Subscribe to read more
Audit directions
a Aaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaa Aaaaaaa Aaaaa Aaaaaaa Aaaaaaaaaa Aaaaa Aaaaa Aaaaaa Aaaaaaaaaa Aaaa Aaaa Aaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaa Aaaaaaa Aaa Aaaaaa Aaa Aaaaaaa Aaaaaaa Aaaa a Aaaaa Aaaaaaaaaaa Aaaaaaaa Aaaaaaaaaa Aaaaa Aaaaaaa Aaaaaa Aaaa Aaaaaaaaaaaa Aaaaaaaaaaaa Aaaaaaaaaa Aa Aaa Aaaaaaaaaaaaaaaa Aaaa Aaaaaaaaa Aaaaa Aaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aa Aaaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaa Aaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaa Aaaaa Aaaaaaa Aaaaaaaaaaaaaa Aaaa Aaa Aa Aaaaaaa Aaaaa Aaaaaaaa
a Aaaaaaaaaaa Aa Aaaaaaaaaaa Aaaaaaaa Aa Aaaaaaa Aaaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaa Aaaaaaa Aaaaaaa Aaaaa Aa Aaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaaaaaaaaaa Aaaa Aaaaa Aaaaa Aaaaa Aaaaaaa Aaaaa Aaaaaaaa Aaaaaa Aaaa Aa Aaaaaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaa Aaaaaa Aaaaaa Aa Aaaaaa Aaaaaaaaa Aaa Aaaaa Aaa Aaaaa Aaaa Aaa Aaaaaaaaaaaaaa Aaaaaaaa Aaa Aaaaa Aaa Aaa Aaaaaaaaaaa Aaaa Aa Aaa Aaaaaaaa
a Aaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa a Aaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaaa Aaaa Aaa Aaaaa Aaaaaaaa Aaaaaa Aaaaaaaaaaa Aa Aaaaaaaa Aaaaaaa Aaaa Aaaaaaaaa Aaaaaa Aaaaaaaaaaa Aaaaa Aaaaa Aaaa Aaaa Aaaaa Aaaa Aaa Aaaaa Aaaaaaaa Aaaaaaaa Aaaaa Aa Aaaaa Aaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaaa Aaaaaaa Aaaa Aaaaaaa Aaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaa Aaaaa Aaa Aaa Aaaaaa Aaaaaaaa
🔒Multiple audit patterns identified for proxy bypass variants across WebKit's network subsystems, with concrete search targets
Subscribe to read more