High chrome Logic Error ⚠️ Exploited in the wild 🔧 Commit mapped

Overview

High
Severity
CVSS
Yes
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in V8
DescriptionInappropriate implementation in V8
ComponentV8
Bug ClassLogic Error
Tracker491410818
Fix commit7076ba135fab (v8/v8) +7/-3
CISA KEVNot listed
CreditedGoogle Threat Analysis Group
Disclosed2026-03-12

Background

Maglev
V8’s mid-tier optimizing compiler that builds an SSA graph from bytecode to produce faster machine code than the baseline interpreter.
Phi untagging
A Maglev pass that rewrites tagged SSA Phi nodes into untagged (raw integer or float) representations to avoid boxing values across control-flow merges.
Tagged value
A V8 value representation where a machine word encodes either a small integer (Smi) or a pointer to a heap object, so the runtime can distinguish types.
`ForceHeapObject` / retagging
The operation that converts an untagged raw value back into a proper tagged heap object when a later use requires the tagged form.

Root Cause Analysis

The vulnerable code path is Maglev’s Phi untagging pass, controlled by the v8_flags.maglev_untagged_phis flag defined in flag-definitions.h, which transforms tagged Phi nodes into untagged representations to elide boxing at control-flow merge points. The correctness invariant this pass must maintain is that whenever an untagged Phi value flows to a use expecting a tagged value, it is faithfully retagged (via ForceHeapObject when a Smi cannot hold it, as the accompanying test regress-490450922-3.js exercises for 0x7fffffff).

The bug is a class of “inappropriate implementation” logic errors in which this untagging/retagging accounting was unsound, so an optimized function could observe or store a mis-typed value (for example an out-of-range integer or a value that was never correctly retagged). Because the accumulated defects in the pass were numerous enough that individual fixes were not keeping up, the fix disables the entire pass by default rather than patching one specific miscompilation. Flipping maglev_untagged_phis to false forces Maglev to keep Phi values tagged, eliminating the unsound representation conversions and the miscompilations that flowed from them.

Key insight
The single core mistake is that Maglev’s Phi untagging pass performed representation changes on merged SSA values without soundly guaranteeing correct retagging at every use, producing miscompiled code; the fix sidesteps the whole error class by disabling maglev_untagged_phis by default until the pass can be made correct.

Attack Path

  1. Deliver script The attacker gets a victim to load a page whose JavaScript is designed to trigger Maglev optimization of a carefully shaped function.
  2. Force optimization The script warms up a function so V8 promotes it to Maglev, where the buggy Phi untagging pass runs on a Phi at a control-flow merge (as %OptimizeFunctionOnNextCall(foo) does in the regression test).
  3. Trigger unsound untagging Inputs are chosen so an untagged Phi carries a value that is not soundly retagged, causing the optimized code to treat a value as the wrong representation or type.
  4. Confuse types or values The miscompiled function reads or writes a value with an incorrect representation, breaking V8’s type/value invariants inside the optimized code.

Impact Assessment

An attacker who can run JavaScript in the renderer gains a logic/type-confusion primitive from a V8 miscompilation, executing within the sandboxed renderer process. The precondition is that the victim loads attacker-controlled script and that the targeted function reaches the Maglev tier with Phi untagging enabled, which was the default before this change. The concrete exploit primitives are not established by the diff alone, but such optimizer miscompilations in V8 are typically stepping stones toward memory corruption in the renderer.

Files Changed

  • src/flags/flag-definitions.h
  • test/mjsunit/turbolev/regress-490450922-3.js

Audit Directions

  • Optimizer representation changes
    Review every Maglev/Turbolev pass that converts between tagged and untagged representations and confirm each untagged value is soundly retagged (ForceHeapObject where a Smi cannot hold it) at all uses.
  • Feature-flag guarded miscompilations
    Treat flags like maglev_untagged_phis, maglev_hoist_osr_value_phi_untagging, and similar compiler toggles as re-enablement risk points and re-audit the underlying pass before any of them is flipped back on.
  • Merge-point value flow
    Audit Phi handling at control-flow merges for values near representation boundaries (e.g. 0x7fffffff, out-of-Smi-range integers, and float/int transitions) where type or range assumptions can be silently violated.
From 7076ba135fab58910afe9bc8a828dfe1e40c4355 Mon Sep 17 00:00:00 2001
From: Darius Mercadier <dmercadier@chromium.org>
Date: Tue, 10 Mar 2026 18:01:59 +0100
Subject: [PATCH] [maglev] disable Phi untagging

There are currently a bit too many issues with Phi untagging; let's
disable it by default until we get things under control.

Bug: 491410818
Change-Id: I98a4884b5374fad9ac98df0ab57c4203a1ce8403
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7653638
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
Auto-Submit: Darius Mercadier <dmercadier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#105711}
---

diff --git a/src/flags/flag-definitions.h b/src/flags/flag-definitions.h
index 26ce19c..49840a8 100644
--- a/src/flags/flag-definitions.h
+++ b/src/flags/flag-definitions.h
@@ -746,7 +746,7 @@
 
 DEFINE_BOOL(maglev_reuse_stack_slots, true,
             "reuse stack slots in the maglev optimizing compiler")
-DEFINE_BOOL(maglev_untagged_phis, true,
+DEFINE_BOOL(maglev_untagged_phis, false,
             "enable phi untagging in the maglev optimizing compiler")
 DEFINE_BOOL(maglev_hoist_osr_value_phi_untagging, true,
             "enable phi untagging to hoist untagging of osr values")
diff --git a/test/mjsunit/turbolev/regress-490450922-3.js b/test/mjsunit/turbolev/regress-490450922-3.js
index 479591f..f688d74 100644
--- a/test/mjsunit/turbolev/regress-490450922-3.js
+++ b/test/mjsunit/turbolev/regress-490450922-3.js
@@ -22,10 +22,14 @@
 %OptimizeFunctionOnNextCall(foo);
 foo(true);
 assertEquals(0x7fffffff, o.x);
-assertOptimized(foo);
+// TODO(dmercadier): re-enable this assertOptimized once Phi untagging has been
+// re-enabled.
+// assertOptimized(foo);
 
 // Even with a Smi it should be fine because we should ForceHeapObject when
 // retagging.
 foo(false);
 assertEquals(42, o.x);
-assertOptimized(foo);
+// TODO(dmercadier): re-enable this assertOptimized once Phi untagging has been
+// re-enabled.
+//assertOptimized(foo);
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/test/mjsunit/turbolev/regress-490450922-3.js b/test/mjsunit/turbolev/regress-490450922-3.js
index 479591f..f688d74 100644
--- a/test/mjsunit/turbolev/regress-490450922-3.js
+++ b/test/mjsunit/turbolev/regress-490450922-3.js
@@ -22,10 +22,14 @@
 %OptimizeFunctionOnNextCall(foo);
 foo(true);
 assertEquals(0x7fffffff, o.x);
-assertOptimized(foo);
+// TODO(dmercadier): re-enable this assertOptimized once Phi untagging has been
+// re-enabled.
+// assertOptimized(foo);
 
 // Even with a Smi it should be fine because we should ForceHeapObject when
 // retagging.
 foo(false);
 assertEquals(42, o.x);
-assertOptimized(foo);
+// TODO(dmercadier): re-enable this assertOptimized once Phi untagging has been
+// re-enabled.
+//assertOptimized(foo);
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.