A race condition in Safari's JIT compiler hands the keys to the house through an unlocked browser tab
CVE-2024-23222 is a type confusion born from a TOCTOU race in WebKit's JavaScriptCore DFG JIT compiler. The vulnerable function Graph::tryGetConstantProperty() reads a JavaScript property on a background compiler thread, releases its cell lock, and returns a raw heap pointer. Between lock release and next use, the main thread can replace the property and trigger garbage collection, freeing the cell the compiler thread still holds. Attackers shape the heap so the freed cell is reallocated with attacker-controlled data, turning the stale pointer into an arbitrary read/write primitive inside the WebContent sandbox. Every Apple platform shipping WebKit is affected: iOS < 17.3 / < 16.7.5 / < 15.8.7, iPadOS (same), macOS Sonoma < 14.3, macOS Ventura < 13.6.4, macOS Monterey < 12.7.3, Safari < 17.3, tvOS < 17.3, visionOS < 1.0.2, plus WebKitGTK < 2.42.5 and WPE WebKit < 2.42.5 on Linux.
Apple's CVSS 8.8 HIGH is honest. The UI:R (user must visit a page) is the only friction in the CVSS vector, and real-world watering-hole campaigns proved it is trivially satisfied: hidden iframes on compromised Ukrainian retail and finance sites (UNC6353), fraudulent crypto exchanges (UNC6691), and surveillance-vendor infrastructure delivered the exploit silently. The Coruna exploit kit chains this WebKit RCE with sandbox escapes and kernel privilege escalation to achieve full device compromise on iOS 13.0–17.2.1 — and iVerify estimated at least 42,000 iPhones were compromised in the Chinese cybercrime wave alone. This is not a theoretical risk — it is a documented, industrialized attack.
5 steps from start to impact.
Victim navigates to attacker-controlled or compromised page
group.html or analytics.html in the Coruna kit). In documented campaigns, legitimate Ukrainian retail and finance websites were compromised to serve the iframe only to geofenced iPhone users. No click, download, or dialog is required — the iframe executes automatically.- Victim uses a vulnerable WebKit-based browser (Safari on macOS, any browser on iOS)
- Victim navigates to a compromised or attacker-controlled site
- MDM-managed fleets with enforced OS minimums above iOS 17.3 / macOS 14.3 are not reachable
- Apple's Lockdown Mode blocks the exploit entirely by disabling JIT
JavaScript triggers TOCTOU race in DFG JIT compiler
- WebKit < 17.3 with DFG JIT enabled (the default on all Apple platforms)
- The race window is naturally nanosecond-scale on x86_64 (the FuzzySecurity PoC inserts a 500ms sleep for determinism); ARM64's weak memory model makes it reliable on iPhones
Attacker gains arbitrary R/W in WebContent process
addrof / fakeobj primitives to achieve full read/write within the renderer sandbox. This is the initial code execution foothold. The attacker can now read and write arbitrary memory within the sandboxed WebContent process but cannot yet access the filesystem, keychain, or kernel.- Successful race in Step 2
- The WebContent process is sandboxed; attacker cannot touch the filesystem, keychain, or kernel without additional exploits
Sandbox escape via chained vulnerability
- A second, unpatched sandbox-escape vulnerability present on the device
- iOS version within the kit's supported range (13.0–17.2.1)
- Patching CVE-2024-23222 alone breaks the chain — the entry point is eliminated
- Devices on iOS 17.3+ are immune even if the sandbox escape CVE remains unpatched
Kernel privilege escalation and persistent implant
- Unpatched kernel vulnerability matching the device's iOS version
- Multiple kernel CVEs must be unpatched simultaneously; Apple's Rapid Security Responses patch kernel bugs independently of major OS releases
apt upgrade webkit2gtk). Deploy within 30 days per noisgate HIGH remediation SLA.- Network-level WAF / IDS signatures. The exploit payload is standard JavaScript over HTTPS. TLS inspection would be required, and even then, the Coruna kit's JavaScript is obfuscated and polymorphic. Generic WAF rules will not catch it.
- Disabling JavaScript globally. While this prevents exploitation, it breaks virtually all modern web applications and is not viable for a production workforce.
- VPN-only browsing policies. Routing traffic through a corporate VPN does not inspect or block malicious JavaScript; it only changes the network path. The exploit executes in the browser regardless.
- Standard file-based antivirus on macOS. Traditional AV does not inspect in-memory JIT compilation artifacts. The exploit operates entirely in memory within the WebContent process and writes no malicious files to disk during the initial RCE phase.
The supporting signals.
| In-the-wild status | Confirmed exploited as zero-day. Weaponized in the Coruna iOS exploit kit (module: Cassowary). Three campaigns: UNC6353 (Russian espionage, Ukraine watering holes, mid-2025), UNC6691 (Chinese cybercrime, fake crypto exchanges, 42K+ devices), unnamed surveillance vendor (Feb 2025). GTIG coordinated remediation with CERT-UA. |
|---|---|
| Proof-of-concept | Public. FuzzySecurity/Cassowary-CVE-2024-23222-x86_64 (Linux x86_64 adaptation, requires ASan debug build + 500ms sleep). Full weaponized Coruna kit analyzed by Califio. CIRCL Vulnerability-Lookup aggregates 16 exploitation sightings and 4 published PoCs. |
| EPSS | 0.10593 — 90th+ percentile. High predicted exploitation probability, consistent with confirmed in-the-wild use. |
| KEV status | Listed 2024-01-23 (same day as Apple's advisory). Federal agency due date was 2024-02-13. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H = 8.8 HIGH. Network-reachable, low complexity, no privileges, user interaction required. Scope unchanged — impact nominally confined to WebContent sandbox, though real-world chains escape it. |
| Affected versions | iOS < 17.3 / < 16.7.5 / < 15.8.7, iPadOS (same), macOS Sonoma < 14.3, macOS Ventura < 13.6.4, macOS Monterey < 12.7.3, Safari < 17.3, tvOS < 17.3, visionOS < 1.0.2, WebKitGTK < 2.42.5, WPE WebKit < 2.42.5 |
| Fixed versions | iOS 17.3 / 16.7.5 / 15.8.7, iPadOS 17.3 / 16.7.5 / 15.8.7, macOS Sonoma 14.3, macOS Ventura 13.6.4, macOS Monterey 12.7.3, Safari 17.3, tvOS 17.3, visionOS 1.0.2. Linux: WebKitGTK 2.42.5, WPE WebKit 2.42.5. Debian backport: webkit2gtk 2.42.5-1~deb12u1. |
| Scanning / exposure | Not scannable via Shodan/GreyNoise (client-side browser vuln, not a listening service). Exposure is measured by MDM fleet OS version distribution — any device below fixed OS versions is vulnerable when browsing. |
| Disclosure date | 2024-01-22 (Apple advisory), 2024-01-23 (NVD, KEV listing). Coruna kit publicly analyzed March 3, 2026. |
| Researcher / org | Originally reported to Apple (reporter not publicly credited). Coruna kit reverse-engineered by Califio, GTIG, iVerify, and CERT-UA. FuzzySecurity produced the public x86_64 PoC adaptation. |
Sources.
- CISA KEV: CVE-2024-23222 added 2024-01-23
- NVD: CVE-2024-23222
- Coruna exploit kit — Wikipedia
- Califio: Coruna Stage 1 writeup (Cassowary technical analysis)
- FuzzySecurity: Cassowary CVE-2024-23222 x86_64 PoC
- SOCRadar: Apple zero-day CVE-2024-23222
- Help Net Security: Apple fixes actively exploited WebKit zero-day
- WebKitGTK Security Advisory WSA-2024-0001
Why this verdict
- KEV-listed zero-day with multi-actor weaponization. Three independent threat groups (UNC6353, UNC6691, a surveillance vendor) deployed this in production campaigns. CISA added it to KEV on day one. This alone floors the verdict at HIGH regardless of friction.
- Industrialized exploit kit eliminates attacker skill barrier. The Coruna framework packages CVE-2024-23222 as a turnkey module with fingerprinting, geofencing, and automatic chain selection for iOS 13–17.2. An operator does not need to write a single line of exploit code.
- 42,000+ confirmed device compromises validate real-world impact. iVerify's telemetry from the UNC6691 campaign alone counted at least 42,000 iPhones. This is mass exploitation at scale, not a theoretical PoC.
- Role multiplier: corporate mobile endpoints. WebKit is the mandatory rendering engine for all iOS browsers and the default engine for Safari on macOS. Corporate iPhones and Macs are used by executives, IT admins, finance, and legal — users with access to email, VPN, SSO tokens, MDM admin consoles, and cloud dashboards. A compromised executive iPhone yields Okta push approvals, VPN credentials, and corporate email. Blast radius is host-level initially but escalates to tenant-level or domain-level via credential theft. WebKit is not a canonically high-value-role component (not a DC, hypervisor, or IdP), so the floor is HIGH, not CRITICAL.
- Friction: user interaction is near-zero in watering-hole delivery. The CVSS
UI:Rrequirement is satisfied by visiting any compromised page — no click, no download, no dialog. Coruna's hidden iframe means the user's only 'interaction' is navigating to a legitimate-looking website.
Why not higher?
The vulnerability is a client-side browser engine flaw, not a server-side or identity-infrastructure component. Exploitation requires user interaction (visiting a page), a vulnerable OS version, and chaining with separate sandbox-escape and kernel-privesc CVEs for full device compromise. The WebContent sandbox limits the initial blast radius to the renderer process. WebKit does not occupy a canonically high-value deployment role (it is not an IdP, CA, hypervisor, or domain controller), so the CRITICAL floor does not apply.
Why not lower?
KEV listing with confirmed multi-actor exploitation categorically prevents any downgrade below HIGH. The EPSS score (0.10593, 90th+ percentile) independently confirms high exploitation probability. The Coruna kit proves the full chain is reliable and industrialized. Watering holes satisfy UI:R trivially, and 42,000+ confirmed compromises leave zero room for 'theoretical risk' discounting.
Crowdsourced verification payload.
Run on each macOS or Linux target host (no elevated privileges required). Invoke: bash check_cve_2024_23222.sh. On macOS it checks the Safari and macOS version; on Linux it checks the installed WebKitGTK / WPE WebKit package version. For iOS/iPadOS, query your MDM for device OS versions below 17.3 / 16.7.5 / 15.8.7.
#!/usr/bin/env bash
# check_cve_2024_23222.sh
# Checks whether the host is vulnerable to CVE-2024-23222
# (WebKit type confusion in JSC DFG JIT)
# Exit codes: 1 = VULNERABLE, 0 = PATCHED, 2 = UNKNOWN
set -euo pipefail
VULNERABLE=1
PATCHED=0
UNKNOWN=2
# Compare two version strings (returns 0 if $1 >= $2)
version_gte() {
printf '%s\n%s' "$1" "$2" | sort -t. -k1,1n -k2,2n -k3,3n -C 2>/dev/null
return $?
}
if [[ "$(uname -s)" == "Darwin" ]]; then
SAFARI_PLIST="/Applications/Safari.app/Contents/Info.plist"
if [[ -f "$SAFARI_PLIST" ]]; then
SAFARI_VER=$(/usr/libexec/PlistBuddy -c 'Print CFBundleShortVersionString' "$SAFARI_PLIST" 2>/dev/null || echo "")
if [[ -n "$SAFARI_VER" ]]; then
if version_gte "$SAFARI_VER" "17.3"; then
echo "PATCHED — Safari $SAFARI_VER >= 17.3"
exit $PATCHED
else
echo "VULNERABLE — Safari $SAFARI_VER < 17.3"
exit $VULNERABLE
fi
fi
fi
MACOS_VER=$(sw_vers -productVersion 2>/dev/null || echo "")
if [[ -n "$MACOS_VER" ]]; then
MAJOR=$(echo "$MACOS_VER" | cut -d. -f1)
case "$MAJOR" in
14)
if version_gte "$MACOS_VER" "14.3"; then
echo "PATCHED — macOS $MACOS_VER (Sonoma >= 14.3)"
exit $PATCHED
else
echo "VULNERABLE — macOS $MACOS_VER (Sonoma < 14.3)"
exit $VULNERABLE
fi
;;
13)
if version_gte "$MACOS_VER" "13.6.4"; then
echo "PATCHED — macOS $MACOS_VER (Ventura >= 13.6.4)"
exit $PATCHED
else
echo "VULNERABLE — macOS $MACOS_VER (Ventura < 13.6.4)"
exit $VULNERABLE
fi
;;
12)
if version_gte "$MACOS_VER" "12.7.3"; then
echo "PATCHED — macOS $MACOS_VER (Monterey >= 12.7.3)"
exit $PATCHED
else
echo "VULNERABLE — macOS $MACOS_VER (Monterey < 12.7.3)"
exit $VULNERABLE
fi
;;
*)
if [[ "$MAJOR" -ge 15 ]]; then
echo "PATCHED — macOS $MACOS_VER (post-Sonoma, not affected)"
exit $PATCHED
else
echo "VULNERABLE — macOS $MACOS_VER (EOL, no patch available)"
exit $VULNERABLE
fi
;;
esac
fi
echo "UNKNOWN — could not determine macOS or Safari version"
exit $UNKNOWN
elif [[ "$(uname -s)" == "Linux" ]]; then
WEBKIT_VER=""
if command -v dpkg-query &>/dev/null; then
WEBKIT_VER=$(dpkg-query -W -f='${Version}' libwebkit2gtk-4.0-37 2>/dev/null | sed 's/-.*//' || echo "")
[[ -z "$WEBKIT_VER" ]] && WEBKIT_VER=$(dpkg-query -W -f='${Version}' libwebkit2gtk-4.1-0 2>/dev/null | sed 's/-.*//' || echo "")
elif command -v rpm &>/dev/null; then
WEBKIT_VER=$(rpm -q --qf '%{VERSION}' webkit2gtk3 2>/dev/null || echo "")
[[ "$WEBKIT_VER" == *"not installed"* ]] && WEBKIT_VER=""
fi
if [[ -n "$WEBKIT_VER" ]]; then
if version_gte "$WEBKIT_VER" "2.42.5"; then
echo "PATCHED — WebKitGTK $WEBKIT_VER >= 2.42.5"
exit $PATCHED
else
echo "VULNERABLE — WebKitGTK $WEBKIT_VER < 2.42.5"
exit $VULNERABLE
fi
fi
if command -v dpkg-query &>/dev/null; then
WEBKIT_VER=$(dpkg-query -W -f='${Version}' libwpewebkit-1.0-3 2>/dev/null | sed 's/-.*//' || echo "")
fi
if [[ -n "$WEBKIT_VER" ]]; then
if version_gte "$WEBKIT_VER" "2.42.5"; then
echo "PATCHED — WPE WebKit $WEBKIT_VER >= 2.42.5"
exit $PATCHED
else
echo "VULNERABLE — WPE WebKit $WEBKIT_VER < 2.42.5"
exit $VULNERABLE
fi
fi
echo "UNKNOWN — WebKitGTK/WPE WebKit not found on this Linux host"
exit $UNKNOWN
else
echo "UNKNOWN — unsupported platform $(uname -s)"
exit $UNKNOWN
fi