High CVSS 5.5 webkit Bypass 🔧 Commit mapped

Overview

High
Severity
5.5
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionAn app may be able to access sensitive user data
ComponentWebKit UIProcess
Bug ClassBypass
Tracker295941
Fix commit50b0e0bcc62b (WebKit/WebKit) +296/-4
CWECWE-284
CVSS vectorCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedWojciech Regula of SecuRing (wojciechregula.blog)
Disclosed2025-12-12

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.

Key insight
Media-capture permission grants were cached and reused by origin without regard to whether the page came from a web archive, so a crafted archive could inherit a prior grant; forcing archive-loaded pages to always prompt (and never cache) closes the bypass.

Attack Path

  1. 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).
  2. Get the user to open it The user opens the web archive, loading its content into WebKit as a web-archive page.
  3. Reuse the cached grant Pre-patch, hasGrantedRequest matches the cached grant for the origin and auto-approves capture without prompting.
  4. Access sensitive data The archive content activates camera/microphone/geolocation and exfiltrates sensitive user data without consent.

Impact Assessment

An access-control / privacy bypass in the UI process with no memory corruption: opening a crafted web archive could grant it camera, microphone, or geolocation access by reusing cached permissions, exposing sensitive user data. It requires the user to open a malicious .webarchive, but the outcome — silent sensor access — is serious (advisory: access sensitive user data).

Changed Functions

FunctionChangeNotes
UserMediaPermissionRequestManagerProxy::grantRequest / denyRequest
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
modified Skips caching the grant/deny (shouldCacheResult = !page->didLoadWebArchive()) when the page was loaded from a web archive.
UserMediaPermissionRequestManagerProxy::hasGrantedRequest
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
modified Returns false (forcing a prompt) when page->didLoadWebArchive(), so archive pages never auto-approve from cache.
WebPageProxy::shouldAlwaysPromptForPermission
Source/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.cpp
  • Source/WebKit/UIProcess/WebPageProxy.cpp
  • Source/WebKit/UIProcess/WebPageProxy.h
  • Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
  • Tools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mm
  • Tools/TestWebKitAPI/Tests/WebKitCocoa/NotificationAPI.mm
  • Tools/TestWebKitAPI/Tests/WebKitCocoa/UIDelegate.mm
  • Tools/TestWebKitAPI/Tests/WebKitCocoa/example.webarchive

Audit Directions

  • Other cached permissions vs web archive
    Audit permission/state caches (notifications, storage access, geolocation tokens) for reuse on didLoadWebArchive() pages without an always-prompt guard.
  • Origin trust for archives
    Grep UIProcess for permission/grant lookups keyed only on security origin that do not distinguish web-archive-loaded content.

Original Bug Report

The reporter's bug is still restricted on the tracker.