Released March 11, 2025

CVE-2025-24201

CVSS 10 severity critical CWE-787 ⚠ CISA KEV vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Overview

Impact:

Description: Maliciously crafted web content may be able to break out of Web Content sandbox. This is a supplementary fix for an attack that was blocked in iOS 17.2. (Apple is aware of a report that this issue may have been exploited in an extremely sophisticated attack against specific targeted individuals on versions of iOS before iOS 17.2.)

Researchers: Apple

Key insight. WebGL enable/disable forwarded PRIMITIVE_RESTART_FIXED_INDEX — a capability the implementation must manage per WebGL version — straight to GL, letting content desynchronize primitive-restart state into an out-of-bounds condition; rejecting the toggle restores control to the implementation.

Patch Details

diff --git a/Source/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp b/Source/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp
index 55f23b3eb337..bbe382cf413d 100644
--- a/Source/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp
+++ b/Source/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp
@@ -1187,7 +1187,11 @@ void GraphicsContextGLANGLE::disable(GCGLenum cap)
 {
     if (!makeContextCurrent())
         return;
-
+    if (cap == PRIMITIVE_RESTART_FIXED_INDEX) {
+        if (m_isForWebGL2)
+            addError(GCGLErrorCode::InvalidOperation);
+        return;
+    }
     GL_Disable(cap);
 }
 
@@ -1221,7 +1225,11 @@ void GraphicsContextGLANGLE::enable(GCGLenum cap)
 {
     if (!makeContextCurrent())
         return;
-
+    if (cap == PRIMITIVE_RESTART_FIXED_INDEX) {
+        if (!m_isForWebGL2)
+            addError(GCGLErrorCode::InvalidOperation);
+        return;
+    }
     GL_Enable(cap);
 }
 

Background

Advisory: Apple Security Advisory

Attribute Value
CVE CVE-2025-24201
Bugzilla 285858
Component WebKit
Bug Class OOB
Severity medium
Commit 7d784721e440d049…
Advisory Apple Advisory

Terminology

  • ANGLE — WebKit’s translation layer running WebGL on native GPU APIs; its Metal backend executes in the GPU/WebContent graphics path.
  • PRIMITIVE_RESTART_FIXED_INDEX — A GL capability controlling primitive-restart in indexed draws; in WebGL2 it is implicitly always on and not app-toggleable, and absent in WebGL1.
  • WebGL enable/disable — APIs that set GL capabilities; forwarding an implementation-managed capability from untrusted content desynchronizes GL state.

Root Cause Analysis

This is a supplementary fix (exploited in the wild before iOS 17.2) for an out-of-bounds sandbox escape via WebGL primitive-restart state in the ANGLE Metal backend. WebGL exposes enable(cap)/disable(cap); GraphicsContextGLANGLE::enable/disable forwarded the capability straight to GL_Enable/GL_Disable. PRIMITIVE_RESTART_FIXED_INDEX must not be toggled by web content: in WebGL2 it is always enabled and managed by the implementation, and in WebGL1 it does not exist. Allowing content to enable or disable it drove ANGLE/GL into an inconsistent primitive-restart configuration that, combined with index buffers during geometry processing, produced out-of-bounds memory access in the GPU pipeline — a corruption primitive used to break out of the WebContent sandbox. The fix special-cases the capability: disable(PRIMITIVE_RESTART_FIXED_INDEX) raises InvalidOperation in WebGL2 and returns without forwarding to GL; enable(PRIMITIVE_RESTART_FIXED_INDEX) raises InvalidOperation when NOT in WebGL2 and returns. The restored invariant is that primitive-restart state is controlled by the implementation per WebGL version, never by untrusted enable/disable calls.

Attack Path

1. Create a WebGL context

Open a WebGL1 or WebGL2 context from web content.

2. Toggle the forbidden capability

Call gl.enable/gl.disable(PRIMITIVE_RESTART_FIXED_INDEX), which pre-patch forwarded straight to ANGLE/GL.

3. Desynchronize primitive-restart state

Combined with crafted index buffers, the inconsistent state drives out-of-bounds access in the GPU geometry pipeline.

4. Escape the sandbox

Leverage the OOB corruption to break out of the WebContent sandbox (observed in a sophisticated in-the-wild attack).

Impact Assessment

An out-of-bounds memory-corruption primitive reachable from ordinary WebGL content that was used to escape the WebContent sandbox — the advisory notes exploitation in an extremely sophisticated targeted attack and frames it as a supplementary fix. Despite the ‘medium’ label the real-world impact is sandbox escape, among the most serious outcomes for renderer-reachable bugs.

Audit Directions

Other implementation-managed capabilities

Audit GraphicsContextGLANGLE::enable/disable and cap-forwarding for other GL capabilities that WebGL1/WebGL2 must manage internally rather than accept from content.

WebGL version gating

Grep for m_isForWebGL2 checks around GL state to find capabilities/queries valid in only one WebGL version that are not gated.

Changed Functions

Function File Change Note
GraphicsContextGLANGLE::disable Source/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp modified For PRIMITIVE_RESTART_FIXED_INDEX raises InvalidOperation in WebGL2 and returns without forwarding to GL_Disable.
GraphicsContextGLANGLE::enable Source/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp modified For PRIMITIVE_RESTART_FIXED_INDEX raises InvalidOperation when not WebGL2 and returns without forwarding to GL_Enable.