Automated Threat Modeling

Electron CVE-2026-34774: Brief Summary of a Use-After-Free in Offscreen Rendering Child Windows

A brief summary of CVE-2026-34774, a high-severity use-after-free in Electron's offscreen rendering path that affects applications that permit child windows. It covers the patch and the affected versions.

CVE Analysis

8 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-04-03

Electron CVE-2026-34774: Brief Summary of a Use-After-Free in Offscreen Rendering Child Windows
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A use-after-free in Electron's offscreen rendering path creates a memory corruption risk for any desktop application that combines offscreen rendering with permissive child window creation. Electron powers VS Code, Slack, Discord, Signal, Docker, Notion, and AI tools from OpenAI and Anthropic, so a framework-level memory safety bug has a large potential blast radius, even when the vulnerable configuration is narrow.

CVE-2026-34774 carries a CVSS 8.1 (High) score and affects Electron versions prior to 39.8.1, 40.7.0, and 41.0.0. The flaw is triggered when a parent offscreen WebContents is destroyed while a child window spawned via window.open() is still alive. Later paint frames on the orphaned child dereference freed memory that belonged to the destroyed parent. Applications that do not use offscreen rendering (webPreferences.offscreen: true), or that deny child windows through their setWindowOpenHandler, are entirely unaffected.

Technical Information

Root Cause: Unsafe base::Unretained(this) in Paint Callback Binding

The vulnerability comes from how Electron binds the paint callback when it creates a child window from an offscreen-rendered parent. Inside MaybeOverrideCreateParamsForNewWindow in shell/browser/api/electron_api_web_contents.cc, the code constructs an OffScreenWebContentsView for the child and binds its paint callback directly to the parent WebContents using base::Unretained(this):

// Before the fix — vulnerable code path auto* view = new OffScreenWebContentsView( false, offscreen_use_shared_texture_, offscreen_shared_texture_pixel_format_, base::BindRepeating(&WebContents::OnPaint, base::Unretained(this)));

The problem is object lifetimes. When MaybeOverrideCreateParamsForNewWindow runs, the child WebContents does not exist yet, so the code points the callback at the parent instead. base::Unretained(this) creates a raw pointer with no lifetime checks. It does not invalidate when the referenced object is destroyed, which leaves it dangling.

The Use-After-Free Trigger

The vulnerability is triggered by this sequence:

  1. An Electron application enables offscreen rendering (webPreferences.offscreen: true) and configures setWindowOpenHandler to permit child windows.
  2. A child window is opened via window.open(). During creation, the child's OffScreenWebContentsView paint callback is bound to the parent WebContents via base::Unretained(this).
  3. The parent offscreen WebContents is destroyed (for example, the parent BrowserWindow is closed or garbage collected).
  4. The child window stays open and keeps rendering. When the next paint frame fires, the child's callback invokes WebContents::OnPaint on the freed parent memory.
  5. That dereference of freed memory is a use-after-free (CWE-416). Depending on the state of the heap, the result is a crash or memory corruption.

Attack Vector Analysis

The CVSS 3.1 vector is AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H. The network attack vector (AV:N) means the exploit could be delivered remotely through malicious web content loaded into the vulnerable Electron application. The high attack complexity (AC:H) reflects the specific configuration prerequisites and the precise timing an attacker needs between parent destruction and child paint frames. No privileges (PR:N) and no user interaction (UI:N) are required. A successful exploit would have High impact on confidentiality, integrity, and availability.

An attacker targeting this vulnerability would need to:

  1. Identify an Electron application that uses offscreen rendering and permits child windows.
  2. Deliver content (likely via a loaded URL or injected script) that opens a child window via window.open().
  3. Trigger destruction of the parent offscreen WebContents while the child window is still alive.
  4. Wait for the child window to render a paint frame, which invokes the dangling callback into freed memory.

Patch Information

The Electron team fixed CVE-2026-34774 in commit 5fded6ae, merged on March 10, 2026, via PR #50184. The fix shipped in Electron versions 39.8.1, 40.7.0, and 41.0.0, and is tracked under GitHub Security Advisory GHSA-532v-xpq5-8h95.

The patch adds 17 lines across three files and corrects two design flaws in one targeted refactor. Each change is covered below.

Step 1: Neutralize the Unsafe Binding at Creation Time

In shell/browser/api/electron_api_web_contents.cc, within MaybeOverrideCreateParamsForNewWindow, the dangerous base::BindRepeating(&WebContents::OnPaint, base::Unretained(this)) was replaced with base::DoNothing():

// shell/browser/api/electron_api_web_contents.cc — MaybeOverrideCreateParamsForNewWindow if (is_offscreen) { + // Use a no-op callback here. The real OnPaint callback will be bound + // to the child WebContents in AddNewContents via SetCallback(). auto* view = new OffScreenWebContentsView( false, offscreen_use_shared_texture_, - offscreen_shared_texture_pixel_format_, - base::BindRepeating(&WebContents::OnPaint, base::Unretained(this))); + offscreen_shared_texture_pixel_format_, base::DoNothing()); create_params->view = view; create_params->delegate_view = view; }

The child WebContents still does not exist while the create params are being assembled. The old code filled that gap by pointing at the parent, which created the dangling-pointer hazard. Now a harmless no-op placeholder sits there instead.

Step 2: Rebind the Callback to the Correct Owner

Later in the same file, inside AddNewContents (called once the child WebContents has been fully created), a new block rebinds the paint callback to the child using GetWeakPtr() instead of a raw pointer:

// shell/browser/api/electron_api_web_contents.cc — AddNewContents auto api_web_contents = CreateAndTake(isolate, std::move(new_contents), type); + // Rebind the paint callback to the child WebContents. + if (auto* osr_view = api_web_contents->GetOffScreenWebContentsView()) { + osr_view->SetCallback(base::BindRepeating(&WebContents::OnPaint, + api_web_contents->GetWeakPtr())); + }

GetWeakPtr() is the main safety improvement. A weak pointer invalidates automatically when the referenced object is destroyed, so even if the lifetimes mismatch in some unexpected way, the callback does nothing instead of dereferencing freed memory.

Step 3: Expose SetCallback on the View Class

To support the deferred rebinding, the patch adds a new public method, SetCallback, to OffScreenWebContentsView:

// shell/browser/osr/osr_web_contents_view.h void SetWebContents(content::WebContents*); void SetNativeWindow(NativeWindow* window); + void SetCallback(const OnPaintCallback& callback);
// shell/browser/osr/osr_web_contents_view.cc +void OffScreenWebContentsView::SetCallback(const OnPaintCallback& callback) { + callback_ = callback; +}

This method overwrites the stored callback_ member, replacing the initial base::DoNothing() placeholder with the correctly bound child callback.

The patch removes the cross-lifetime ownership hazard by never binding the paint callback to the parent WebContents. As a safety net, the replacement binding uses GetWeakPtr() rather than base::Unretained(). The full change is 17 additions and 2 deletions across three files, and it touches only the offscreen rendering path.

Affected Systems and Versions

The vulnerability affects Electron applications that meet both of these conditions:

  1. Offscreen rendering is enabled (webPreferences.offscreen: true)
  2. The setWindowOpenHandler permits child windows

Applications that do not use offscreen rendering, or that deny child windows, are not affected.

Release BranchVulnerable VersionsPatched Version
Branch 39Prior to 39.8.139.8.1
Branch 4040.0.0-alpha.1 to prior to 40.7.040.7.0
Branch 4141.0.0-alpha.1 to prior to 41.0.041.0.0

Vendor Security History

Electron is an Impact Project under the OpenJS Foundation and graduated from incubation in June 2020. The project has a dedicated Security Working Group that handles vulnerability reports and coordinates fixes. Its security policy sets out a clear reporting process, with an escalation path to the OpenJS Foundation if responses are delayed. For critical issues, the Security Working Group sends advance Need to Know notifications to trusted partners through private channels, so major application developers can prepare fixes before public disclosure. The CVE-2026-34774 timeline reflects this maturity. The fix was merged on March 10, 2026, the GitHub Security Advisory was published on April 2, 2026, and the CVE record followed on April 3, 2026.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization