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:
- An Electron application enables offscreen rendering (
webPreferences.offscreen: true) and configuressetWindowOpenHandlerto permit child windows. - A child window is opened via
window.open(). During creation, the child'sOffScreenWebContentsViewpaint callback is bound to the parentWebContentsviabase::Unretained(this). - The parent offscreen
WebContentsis destroyed (for example, the parentBrowserWindowis closed or garbage collected). - The child window stays open and keeps rendering. When the next paint frame fires, the child's callback invokes
WebContents::OnPainton the freed parent memory. - 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:
- Identify an Electron application that uses offscreen rendering and permits child windows.
- Deliver content (likely via a loaded URL or injected script) that opens a child window via
window.open(). - Trigger destruction of the parent offscreen
WebContentswhile the child window is still alive. - 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:
- Offscreen rendering is enabled (
webPreferences.offscreen: true) - The
setWindowOpenHandlerpermits child windows
Applications that do not use offscreen rendering, or that deny child windows, are not affected.
| Release Branch | Vulnerable Versions | Patched Version |
|---|---|---|
| Branch 39 | Prior to 39.8.1 | 39.8.1 |
| Branch 40 | 40.0.0-alpha.1 to prior to 40.7.0 | 40.7.0 |
| Branch 41 | 41.0.0-alpha.1 to prior to 41.0.0 | 41.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
- GitHub Security Advisory GHSA-532v-xpq5-8h95
- CVE Record: CVE-2026-34774
- NVD: CVE-2026-34774
- Patch Commit 5fded6ae
- GitHub Advisory Database: CVE-2026-34774
- Snyk Vulnerability: SNYK-JS-ELECTRON-15875869
- Electron Security Documentation
- Electron Security Working Group: Membership and Notifications
- Electron SECURITY.md
- Electron: Why Electron
- Electron becomes an OpenJS Foundation Impact Project



