Low watch CVSS 9.6 chrome Policy Bypass 🔧 Commit mapped

Overview

Low
Severity
9.6
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient policy enforcement in GPU
DescriptionInsufficient policy enforcement in GPU
ComponentGPU
Sub-componentViz
Bug ClassPolicy Bypass
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker496522611
Fix commit8b19dcd1ffef (chromium/src) +27/-0
CWECWE-693
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-03-26 (per vendor advisory)
Fix landed2026-05-20 (public git)
Disclosed2026-06-30
Patch gap41 days — fix public in source before the advisory

Background

Viz / `CompositorFrameSinkSupport`
the GPU-process component that services a renderer’s compositor frame sink over Mojo, including layer-context requests.
`BindLayerContext()`
the Mojo-exposed method that constructs a LayerContextImpl from a renderer-supplied PendingLayerContext, wiring up the “trees in viz” layer-context pipeline.
`features::kTreesInViz`
the runtime feature flag gating the TreesInViz functionality that LayerContextImpl implements.
`LayerContextImpl`
the object created and owned via layer_context_ that drives the layer-context path once bound.

Root Cause Analysis

CompositorFrameSinkSupport::BindLayerContext unconditionally created a LayerContextImpl from the renderer-provided PendingLayerContext without checking whether the kTreesInViz feature was enabled. This meant the TreesInViz layer-context code path could be reached and instantiated in the GPU process even when the feature was supposed to be disabled, so the feature flag did not actually gate the functionality it guarded.

The fix adds an early return when base::FeatureList::IsEnabled(features::kTreesInViz) is false, so BindLayerContext no longer constructs layer_context_ for disabled builds/configurations. The regression test confirms that with the feature disabled, BindLayerContext leaves layer_context_for_testing() null.

Key insight
A feature-gated code path was reachable regardless of its flag; the fix inserts the missing kTreesInViz enablement check at the entry of BindLayerContext so the layer context is only bound when the feature is actually on.

Attack Path

  1. Send a layer-context bind request A renderer (or compromised renderer) issues the Mojo call that reaches CompositorFrameSinkSupport::BindLayerContext with a crafted PendingLayerContext, even in a configuration where kTreesInViz is disabled.
  2. Unguarded instantiation Pre-patch, BindLayerContext creates a LayerContextImpl regardless of the flag, activating the TreesInViz layer-context pipeline that policy intended to keep off.
  3. Exercise the unintended path The renderer can then drive the layer-context surface in the GPU process that should have been unreachable while the feature is disabled.
  4. Downstream consequences Any memory-safety or additional attack surface exposed by the prematurely enabled layer-context code is (inferred); the patch itself only demonstrates the policy/gating failure, not a specific corruption sink.

Impact Assessment

A renderer can reach and activate the kTreesInViz layer-context code path in the GPU process even when the feature flag is disabled, defeating the intended gating of that functionality. The precondition is the ability to issue the layer-context bind Mojo call to Viz, available to a renderer. The advisory rates this as insufficient policy enforcement in GPU; any resulting memory-safety or sandbox impact from the exposed surface is (inferred) and no exploited-in-the-wild status is stated.

Files Changed

  • components/viz/service/frame_sinks/compositor_frame_sink_support.cc
  • components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc

Audit Directions

  • Feature-flag gaps at Mojo entry points
    Audit browser/GPU-process Mojo handlers that instantiate flag-gated subsystems to confirm the enablement check is performed before construction, not merely at the caller.
  • Renderer-reachable constructors
    Review methods that build objects from renderer-supplied Pending* interfaces to ensure their feature/policy preconditions are validated server-side.
  • Flag checked in some paths only
    Where a feature is checked in initialization or UI paths, verify every service-side entry that activates the feature repeats the check.
From 8b19dcd1ffef5628f8b82b461884ef195470ffa2 Mon Sep 17 00:00:00 2001
From: Zhenyao Mo <[email protected]>
Date: Wed, 20 May 2026 08:59:31 -0700
Subject: [PATCH] viz: Support TreesInViz check in BindLayerContext

Bug: 496522611
Change-Id: I149e96384d9c161c6353a936ca90863accf1400c

TEST=viz_unittests

Change-Id: I149e96384d9c161c6353a936ca90863accf1400c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7861920
Auto-Submit: Zhenyao Mo <[email protected]>
Commit-Queue: Vasiliy Telezhnikov <[email protected]>
Reviewed-by: Vasiliy Telezhnikov <[email protected]>
Commit-Queue: Zhenyao Mo <[email protected]>
Reviewed-by: Tzarial <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1633621}
---

diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index d81eba6..8e3368626 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -624,6 +624,9 @@
 void CompositorFrameSinkSupport::BindLayerContext(
     mojom::PendingLayerContext& context,
     mojom::LayerContextSettingsPtr settings) {
+  if (!base::FeatureList::IsEnabled(features::kTreesInViz)) {
+    return;
+  }
   layer_context_ =
       std::make_unique<LayerContextImpl>(this, context, std::move(settings));
 }
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index bec1b6f..b18e905 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -2929,4 +2929,28 @@
   support->SendCompositorFrameAck();
 }
 
+TEST_P(AckOnSurfaceActivationWhenInteractiveTest,
+       TreesInVizDisabledDoesNotBindLayerContext) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(features::kTreesInViz);
+  manager_->RegisterFrameSinkId(kAnotherArbitraryFrameSinkId,
+                                true /* report_activation */);
+  MockCompositorFrameSinkClient mock_client;
+  auto support = std::make_unique<CompositorFrameSinkSupport>(
+      &mock_client, manager_.get(), kAnotherArbitraryFrameSinkId, kIsRoot);
+
+  auto context = mojom::PendingLayerContext::New();
+  mojo::AssociatedRemote<mojom::LayerContext> layer_context;
+  context->receiver = layer_context.BindNewEndpointAndPassReceiver();
+  MockLayerContextClient mock_layer_context_client;
+  mojo::AssociatedReceiver<mojom::LayerContextClient>
+      layer_context_client_receiver(
+          &mock_layer_context_client,
+          context->client.InitWithNewEndpointAndPassReceiver());
+
+  auto settings = mojom::LayerContextSettings::New();
+  support->BindLayerContext(*context, std::move(settings));
+  EXPECT_EQ(support->layer_context_for_testing(), nullptr);
+}
+
 }  // namespace viz
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index bec1b6f..b18e905 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -2929,4 +2929,28 @@
   support->SendCompositorFrameAck();
 }
 
+TEST_P(AckOnSurfaceActivationWhenInteractiveTest,
+       TreesInVizDisabledDoesNotBindLayerContext) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(features::kTreesInViz);
+  manager_->RegisterFrameSinkId(kAnotherArbitraryFrameSinkId,
+                                true /* report_activation */);
+  MockCompositorFrameSinkClient mock_client;
+  auto support = std::make_unique<CompositorFrameSinkSupport>(
+      &mock_client, manager_.get(), kAnotherArbitraryFrameSinkId, kIsRoot);
+
+  auto context = mojom::PendingLayerContext::New();
+  mojo::AssociatedRemote<mojom::LayerContext> layer_context;
+  context->receiver = layer_context.BindNewEndpointAndPassReceiver();
+  MockLayerContextClient mock_layer_context_client;
+  mojo::AssociatedReceiver<mojom::LayerContextClient>
+      layer_context_client_receiver(
+          &mock_layer_context_client,
+          context->client.InitWithNewEndpointAndPassReceiver());
+
+  auto settings = mojom::LayerContextSettings::New();
+  support->BindLayerContext(*context, std::move(settings));
+  EXPECT_EQ(support->layer_context_for_testing(), nullptr);
+}
+
 }  // namespace viz
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.