CVE-2025-46282
Overview
Background
- Web Archive (.webarchive)
- A saved snapshot of a page (content under some origin) that can be opened later; an attacker can craft one presenting a chosen origin.
- Permission caching
- WebKit remembers granted/denied capture permissions per origin to avoid re-prompting; reusing that cache for archive content is unsafe.
- didLoadWebArchive
- A page flag indicating the current content came from a web archive, used to force prompting.
Root Cause Analysis
This fixes a permission bypass where content loaded from a saved Web Archive could silently reuse cached camera/microphone/geolocation grants. WebKit caches media-capture permission decisions per origin so a site does not re-prompt: grantRequest appends to m_grantedRequests, denyRequest appends to m_deniedRequests, and hasGrantedRequest consults m_grantedRequests to auto-approve a matching origin without a prompt. A .webarchive file bundles content under an arbitrary origin; if a user opens a malicious web archive whose origin matches a site the user previously granted capture to (or if the archive can otherwise ride the cache), the archive’s content could obtain camera/microphone/geolocation access WITHOUT a fresh user prompt — accessing sensitive user data.
The fix makes web-archive-loaded pages never populate or reuse the permission cache: grantRequest and denyRequest set shouldCacheResult = !page->didLoadWebArchive() and skip caching when a web archive was loaded; hasGrantedRequest returns false immediately when page->didLoadWebArchive(); and a new WebPageProxy::shouldAlwaysPromptForPermission returns true for Camera/Microphone/Geolocation when the page loaded a web archive.
The restored invariant is that a page loaded from a web archive always prompts for capture/geolocation permissions and cannot inherit or seed cached grants. The impact — reachable by getting a user to open a crafted .webarchive — is unauthorized access to sensitive sensors, not memory corruption.
Attack Path
- Craft a malicious web archive Build a .webarchive presenting content under an origin the user has previously granted (or otherwise able to hit the permission cache).
- Get the user to open it The user opens the web archive, loading its content into WebKit as a web-archive page.
- Reuse the cached grant Pre-patch, hasGrantedRequest matches the cached grant for the origin and auto-approves capture without prompting.
- Access sensitive data The archive content activates camera/microphone/geolocation and exfiltrates sensitive user data without consent.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
UserMediaPermissionRequestManagerProxy::grantRequest / denyRequestSource/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp |
modified | Skips caching the grant/deny (shouldCacheResult = !page->didLoadWebArchive()) when the page was loaded from a web archive. |
UserMediaPermissionRequestManagerProxy::hasGrantedRequestSource/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp |
modified | Returns false (forcing a prompt) when page->didLoadWebArchive(), so archive pages never auto-approve from cache. |
WebPageProxy::shouldAlwaysPromptForPermissionSource/WebKit/UIProcess/WebPageProxy.cpp |
added | Returns true for Camera/Microphone/Geolocation when a web archive was loaded, ensuring those permissions always prompt. |
Files Changed
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cppSource/WebKit/UIProcess/WebPageProxy.cppSource/WebKit/UIProcess/WebPageProxy.hTools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxprojTools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mmTools/TestWebKitAPI/Tests/WebKitCocoa/NotificationAPI.mmTools/TestWebKitAPI/Tests/WebKitCocoa/UIDelegate.mmTools/TestWebKitAPI/Tests/WebKitCocoa/example.webarchive
Audit Directions
- Other cached permissions vs web archiveAudit permission/state caches (notifications, storage access, geolocation tokens) for reuse on didLoadWebArchive() pages without an always-prompt guard.
- Origin trust for archivesGrep UIProcess for permission/grant lookups keyed only on security origin that do not distinguish web-archive-loaded content.