CVE-2024-44212
Overview
Background
- Web archive (.webarchive)
- A single-file snapshot of a page and its subresources that WebKit can load, with its own baseURL origin.
- Ephemeral / non-persistent data store
- A website data store with no on-disk persistence, swapped in for web archive loads to isolate their cookies and storage.
- URL string vs filesystem path
- url.string() is the full serialized URL (scheme, path, query, fragment, encoding); url.fileSystemPath() is the decoded local path only.
- Navigation policy decision
- The UIProcess step that decides how a navigation proceeds, including which data store backs it.
Root Cause Analysis
WebPageProxy::receivedNavigationActionPolicyDecision decides whether a navigation should be loaded in a swapped-in non-persistent (ephemeral) website data store, which is done for web archives so their content is isolated. The webarchive detection tested webarchiveURL.string().endsWith(".webarchive") — i.e. it matched the suffix against the full URL string, which includes the query and fragment and percent-encoding, not just the file path. A file URL for a genuine .webarchive that carries a query or fragment (e.g. file:///path/x.webarchive?a or ...x.webarchive#a) has a .string() that does NOT end in .webarchive, so the archive was not recognized and the ephemeral-store swap was skipped; the archive then loaded in the normal persistent data store, so cookies associated with the archive’s origin were read from / written to the shared persistent store and could reach another origin.
The fix matches against webarchiveURL.fileSystemPath(), the decoded filesystem path with query/fragment stripped, so the .webarchive classification reflects the real file rather than an attacker-manipulable URL string, and the ephemeral-store isolation is applied to exactly the webarchive loads it is meant for.
The restored invariant is that ‘is this a .webarchive load’ is decided from the file path, not from a URL string that can be altered without changing the file. This runs in the UIProcess navigation policy path, not the sandboxed WebContent.
Attack Path
- Host a web archive Get the victim to open a .webarchive file (local file load or substitute data) that should be isolated in an ephemeral data store.
- Perturb the URL string Reference the archive with a URL whose string does not end in ‘.webarchive’ though the file path does — e.g. append a query or fragment (x.webarchive?a / x.webarchive#a).
- Defeat archive detection endsWith on url.string() fails to match, so receivedNavigationActionPolicyDecision does not swap in the non-persistent store.
- Leak cookies across origins The archive loads in the persistent store, so cookies tied to the archive’s baseURL origin are read/written in the shared store and can be sent to another origin.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
WebPageProxy::receivedNavigationActionPolicyDecisionSource/WebKit/UIProcess/WebPageProxy.cpp |
modified | Detects a web archive with webarchiveURL.fileSystemPath().endsWith(".webarchive") instead of webarchiveURL.string().endsWith(...), so query/fragment/encoding can't hide or fake the archive suffix and ephemeral-store isolation is applied correctly. |
Audit Directions
- Other suffix/extension checks on url.string()grep WebKit/WebCore for
.string().endsWith(/.startsWith(/contains(on URLs used for security decisions; prefer fileSystemPath()/path() where a file is meant. - Data-store / storage-partition selectionAudit other branches choosing persistent vs ephemeral stores or storage partitions based on URL shape rather than resolved origin.
- webarchive handlingReview all isWebArchiveMIMEType / .webarchive handling for consistent path-based classification across load, save, and policy paths.