Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in WebRTC
DescriptionUse after free in WebRTC
ComponentWebRTC
Bug ClassUAF
Tracker513049286
Fix commitb9f0b184cb5a (src) +10/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-05-27

Files Changed

  • modules/desktop_capture/linux/wayland/restore_token_manager.cc
  • modules/desktop_capture/linux/wayland/restore_token_manager.h
From b9f0b184cb5a487fcb4910efaf4f84483ddba284 Mon Sep 17 00:00:00 2001
From: Alexander Cooper <alcooper@chromium.org>
Date: Thu, 14 May 2026 13:26:42 -0700
Subject: [PATCH] Guard RestoreTokenManager add/reads with Mutex

The RestoreTokenManager is a singleton who's adds and reads could be
accessed by multiple threads simultaneously. To prevent any potential
issues/collisions, ensure that such accesses happen behind a lock.

Bug: chromium:513049286
Change-Id: I44c1c7977a6d02e1ac3fbe00e6ffc7bc22e41e46
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/472480
Reviewed-by: Mark Foltz <mfoltz@chromium.org>
Auto-Submit: Alexander Cooper <alcooper@chromium.org>
Commit-Queue: Mark Foltz <mfoltz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#47711}
---

diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.cc b/modules/desktop_capture/linux/wayland/restore_token_manager.cc
index ff843c2..101a5af 100644
--- a/modules/desktop_capture/linux/wayland/restore_token_manager.cc
+++ b/modules/desktop_capture/linux/wayland/restore_token_manager.cc
@@ -13,6 +13,7 @@
 #include <string>
 
 #include "modules/desktop_capture/desktop_capturer.h"
+#include "rtc_base/synchronization/mutex.h"
 
 namespace webrtc {
 
@@ -24,15 +25,18 @@
 
 void RestoreTokenManager::AddToken(DesktopCapturer::SourceId id,
                                    const std::string& token) {
+  MutexLock lock(&mutex_);
   restore_tokens_.insert({id, token});
 }
 
 std::string RestoreTokenManager::GetToken(DesktopCapturer::SourceId id) {
+  MutexLock lock(&mutex_);
   const std::string token = restore_tokens_[id];
   return token;
 }
 
 DesktopCapturer::SourceId RestoreTokenManager::GetUnusedId() {
+  MutexLock lock(&mutex_);
   return ++last_source_id_;
 }
 
diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.h b/modules/desktop_capture/linux/wayland/restore_token_manager.h
index 06d3071..120a4b2 100644
--- a/modules/desktop_capture/linux/wayland/restore_token_manager.h
+++ b/modules/desktop_capture/linux/wayland/restore_token_manager.h
@@ -15,6 +15,8 @@
 #include <unordered_map>
 
 #include "modules/desktop_capture/desktop_capturer.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
 
 namespace webrtc {
 
@@ -35,9 +37,11 @@
   RestoreTokenManager() = default;
   ~RestoreTokenManager() = default;
 
-  DesktopCapturer::SourceId last_source_id_ = 0;
+  Mutex mutex_;
+  DesktopCapturer::SourceId last_source_id_ RTC_GUARDED_BY(mutex_) = 0;
 
-  std::unordered_map<DesktopCapturer::SourceId, std::string> restore_tokens_;
+  std::unordered_map<DesktopCapturer::SourceId, std::string> restore_tokens_
+      RTC_GUARDED_BY(mutex_);
 };
 
 }  // namespace webrtc
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential data race in RestoreTokenManager singleton leads to memory corruption in Browser process

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 without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: The RestoreTokenManager singleton in WebRTC’s Wayland desktop capture module lacks any synchronization for its shared state. Concurrent mutation of an internal std::unordered_map from the Browser UI thread and dedicated capture threads can lead to heap corruption or use-after-free. This vulnerability resides in the unsandboxed browser process and is reachable from web content via screen capture requests.

Affected files:

  • third_party/webrtc/modules/desktop_capture/linux/wayland/restore_token_manager.cc
  • third_party/webrtc/modules/desktop_capture/linux/wayland/restore_token_manager.h
  • third_party/webrtc/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc

Estimated timestamp from git blame: 2022-06-06

Description

A potential data race exists in the RestoreTokenManager class used by the PipeWire-based desktop capturer on Linux/Wayland. RestoreTokenManager is a process-wide singleton that manages restore tokens using a std::unordered_map and an integer counter, both of which are accessed without any synchronization primitives (such as mutexes or atomics).

// third_party/webrtc/modules/desktop_capture/linux/wayland/restore_token_manager.h
  DesktopCapturer::SourceId last_source_id_ = 0;
  std::unordered_map<DesktopCapturer::SourceId, std::string> restore_tokens_;

In Chromium, this singleton is accessed concurrently from different threads within the browser process:

  1. Browser UI Thread: On Linux, the UI thread pumps the global GLib main context. The BaseCapturerPipeWire class uses asynchronous GDBus signals to communicate with the XDG Desktop Portal. When a portal response is received (e.g., in OnScreenCastRequestResult), the callback is executed on the UI thread. This callback calls RestoreTokenManager::AddToken, which performs a std::unordered_map::insert operation.
  2. Desktop Capture Threads: Each capture session runs on a dedicated desktopCaptureThread. These threads call RestoreTokenManager::GetToken (during BaseCapturerPipeWire::Start) and RestoreTokenManager::GetUnusedId (during BaseCapturerPipeWire::EnsureVisible). GetToken uses the operator[], which is a mutating operation in C++ (it inserts a default value if the key is not found).

Impact

Concurrent unsynchronized mutation of a std::unordered_map is undefined behavior. If one thread triggers a rehash of the map while another thread is accessing it, it can result in a heap use-after-free (UAF) or corruption of the map’s internal bucket structure. Since this occurs in the browser process, which is not sandboxed, it could potentially be leveraged for an escape from the renderer sandbox and arbitrary code execution with the user’s privileges.

Potential Steps to Reproduce

Note: These are suggested steps; our analysis is based on code review.

  1. On a Linux Wayland system, open a web page that initiates multiple desktop capture requests (e.g., multiple calls to navigator.mediaDevices.getDisplayMedia()).
  2. Rapidly accept the system-level capture prompts. This forces the browser to handle multiple asynchronous portal responses on the UI thread while the capture threads are simultaneously initializing or restarting capture sessions.
  3. Under a ThreadSanitizer (TSAN) build, a data race on RestoreTokenManager::restore_tokens_ should be detected between the UI thread and the background capture threads.
  4. Under AddressSanitizer (ASAN), the race may manifest as a heap-use-after-free during map rehashing.

Suggested Fix

Protect all accesses to restore_tokens_ in RestoreTokenManager with a mutex (e.g., webrtc::Mutex). Additionally, last_source_id_ should be changed to a std::atomic<DesktopCapturer::SourceId> or also be protected by the mutex.

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


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