Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactHeap buffer overflow in WebRTC
DescriptionHeap buffer overflow in WebRTC
ComponentWebRTC
Bug ClassOOB
Tracker520199394
Fix commit15644107234a (src) +15/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-16

Changed Functions

FunctionChangeNotes
if
modules/desktop_capture/win/dxgi_output_duplicator.cc
modified

Files Changed

  • modules/desktop_capture/desktop_frame_rotation.cc
  • modules/desktop_capture/win/dxgi_output_duplicator.cc
From 15644107234aa9bc7a4bf7e9f9a2157a8a9415b4 Mon Sep 17 00:00:00 2001
From: Alexander Cooper <[email protected]>
Date: Mon, 08 Jun 2026 10:13:41 -0700
Subject: [PATCH] Fix OOB write in RotateDesktopFrame and DXGI size mismatch

Upgrade RTC_DCHECK to RTC_CHECK in RotateDesktopFrame to enforce
bounds checks in release builds. Validate captured frame size against
expected unrotated size in DxgiOutputDuplicator::Duplicate to fail
gracefully on resolution changes.

Fixed: chromium:520199394
Change-Id: Iad22c89cf3ef900b0ac58a72ec3a9f8d2e96123b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/479000
Auto-Submit: Alexander Cooper <[email protected]>
Commit-Queue: Alexander Cooper <[email protected]>
Reviewed-by: Mark Foltz <[email protected]>
Cr-Commit-Position: refs/heads/main@{#47937}
---

diff --git a/modules/desktop_capture/desktop_frame_rotation.cc b/modules/desktop_capture/desktop_frame_rotation.cc
index a6b4d16..a7ea388 100644
--- a/modules/desktop_capture/desktop_frame_rotation.cc
+++ b/modules/desktop_capture/desktop_frame_rotation.cc
@@ -99,13 +99,13 @@
                         const DesktopVector& target_offset,
                         DesktopFrame* target) {
   RTC_DCHECK(target);
-  RTC_DCHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect));
+  RTC_CHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect));
   // TODO(bugs.webrtc.org/436974448): Support other pixel formats.
   RTC_CHECK_EQ(FOURCC_ARGB, source.pixel_format());
   // The rectangle in `target`.
   const DesktopRect target_rect =
       RotateAndOffsetRect(source_rect, source.size(), rotation, target_offset);
-  RTC_DCHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect));
+  RTC_CHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect));
 
   if (target_rect.is_empty()) {
     return;
diff --git a/modules/desktop_capture/win/dxgi_output_duplicator.cc b/modules/desktop_capture/win/dxgi_output_duplicator.cc
index f07a55a..946401a 100644
--- a/modules/desktop_capture/win/dxgi_output_duplicator.cc
+++ b/modules/desktop_capture/win/dxgi_output_duplicator.cc
@@ -229,6 +229,19 @@
     // triggers screen flickering?
 
     const DesktopFrame& source = texture_->AsDesktopFrame();
+    // During a resolution transition, DXGI might deliver a frame with the new
+    // size before the controller detects the change and reinitializes.
+    // `unrotated_size_` is cached at initialization and only updated when
+    // this object is recreated. We abort capture on mismatch to force
+    // reinitialization by the |DxgiDuplicatorController|.
+    if (!source.size().equals(unrotated_size_)) {
+      RTC_LOG(LS_WARNING) << "Captured frame size " << source.size().width()
+                        << "x" << source.size().height()
+                        << " does not match expected size "
+                        << unrotated_size_.width() << "x"
+                        << unrotated_size_.height();
+      return false;
+    }
     if (rotation_ != Rotation::CLOCK_WISE_0) {
       for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd();
            it.Advance()) {
Loading diff…

Original Bug Report

reported by [email protected]

Potential Heap Out-Of-Bounds Write in Browser via WebRTC DXGI Desktop Capture Rotation Path

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A potential release-build bounds-enforcement gap in RotateDesktopFrame can allow a heap out-of-bounds write or underflow in the browser process on Windows. When a display-mode or resolution change occurs concurrent with rotated screen capture via the DXGI path, a size divergence between cached and live textures can cause coordinate calculations to bypass debug-only checks. This results in writing screen-pixel bytes to out-of-bounds heap memory via libyuv::ARGBRotate.

Affected files:

  • third_party/webrtc/modules/desktop_capture/desktop_frame_rotation.cc
  • third_party/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.cc
  • third_party/webrtc/modules/desktop_capture/win/dxgi_texture.cc

Estimated timestamp from git blame: 2016-11-30

Description

There is a potential heap out-of-bounds write (or heap underflow write) in the Windows browser process during WebRTC screen capture. The vulnerability stems from an asymmetry in how bounds are enforced in the capture pipeline. While the standard non-rotated copy path at third_party/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.cc:247 utilizes DesktopFrame::CopyPixelsFrom(), which performs release-active bounds validation using RTC_CHECK (fatal in release), the rotated copy path relies on RotateDesktopFrame() which uses debug-only RTC_DCHECK statements.

In release builds (NDEBUG), these RTC_DCHECK statements are compiled out. If a mismatch occurs between the cached capture dimensions and the live frame texture dimensions, coordinate calculations can produce out-of-bounds offsets which are then passed directly to libyuv::ARGBRotate() as raw pointers with no runtime safety boundaries.

Root Cause Analysis

  1. Debug-Only Bounds Check: At third_party/webrtc/modules/desktop_capture/desktop_frame_rotation.cc:102,108:

    RTC_DCHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect));
    ... 
    RTC_DCHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect));
    

    In production builds, these checks are omitted.

  2. Stale vs. Live Size Divergence: DxgiOutputDuplicator caches the unrotated display size (unrotated_size_) at initialization time based on DXGI_OUTPUT_DESC.DesktopCoordinates (at dxgi_output_duplicator.cc:79,147). However, DxgiTexture::CopyFrom() dynamically reads the live texture dimensions per-frame:

    D3D11_TEXTURE2D_DESC desc = {0};
    texture->GetDesc(&desc);
    desktop_size_.set(desc.Width, desc.Height);
    

    (at third_party/webrtc/modules/desktop_capture/win/dxgi_texture.cc:61-63).

  3. Integer Underflow and Pointer Arithmetic: During a resolution transition, if a smaller frame is captured before the duplication object is invalidated, DxgiOutputDuplicator::Duplicate() computes source_rect based on the old, larger cached size but executes RotateDesktopFrame() with the smaller live size. Under CLOCK_WISE_90 rotation, RotateAndOffsetRect computes target_rect.left = size.height() - rect.bottom() + offset.x(). When the live height size.height() is smaller than rect.bottom(), this subtraction underflows to a negative value. Pointer arithmetic in GetFrameDataAtPos() then calculates a pointer pointing prior to the heap-allocated destination buffer (at desktop_frame.cc:140), resulting in a heap underflow write via libyuv::ARGBRotate.

Potential Steps to Trigger

Note: These steps are theoretical/potential as our analysis toolchain does not have the capability to execute code.

  1. Web content requests screen capture via getDisplayMedia(), and the user permits capture of a monitor rotated by 90 degrees.
  2. Screen capture runs in the browser process via ScreenCapturerWinDirectx.
  3. Concurrently, a display-mode or resolution change is triggered on the system.
  4. If IDXGIOutputDuplication::AcquireNextFrame() returns S_OK with a resized frame texture before signaling DXGI_ERROR_ACCESS_LOST, DxgiOutputDuplicator processes the frame with divergent live vs. cached dimensions.
  5. The rotation path calculates a negative target offset, leading libyuv::ARGBRotate to perform a heap out-of-bounds write.

Suggested Fix

  1. Harden Bounds Check: Upgrade the RTC_DCHECK statements inside RotateDesktopFrame() in third_party/webrtc/modules/desktop_capture/desktop_frame_rotation.cc to release-active RTC_CHECK assertions, matching the validation behavior in CopyPixelsFrom():

    RTC_CHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect));
    RTC_CHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect));
    
  2. Validate Input Dimensions: Inside DxgiOutputDuplicator::Duplicate(), explicitly verify that the live source frame size matches unrotated_size_ prior to entering the rotation loop. If a mismatch is detected, abort capture or re-initialize the pipeline.

Evaluated with Chrome root at commit: d8b226a3be7c9c1ac9240c09e14698866c82e4ac


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker