CVE-2026-12441
Overview
Background
- `SelectFileDialogLinuxGtk`
- Chrome’s GTK-backed implementation of the native file open/save dialog on Linux; its destructor tears down any dialog widgets still tracked in
dialogs_. - `GtkWindowDestroy()`
- a helper that synchronously drops the last reference on a GTK dialog widget, disposing and finalizing it and returning its GLib heap allocation immediately.
- `OnFileChooserDestroy()`
- a cleanup routine that, per the commit message, calls
g_object_set_data()on thedialog(to clear transient-parent metadata viaClearAuraTransientParent), which requires the widget to still be a live object. - Use-after-free (UAF)
- accessing memory through a pointer after the underlying object has been freed, here reading/writing GLib object data on an already-finalized
GtkWidget.
Root Cause Analysis
In the destructor loop that iterates over each tracked dialog in dialogs_, the pre-patch code called GtkWindowDestroy(dialog) first and only then called OnFileChooserDestroy(dialog). As the added comment states, GtkWindowDestroy() “synchronously drops the only reference and frees the dialog,” so by the time OnFileChooserDestroy(dialog) ran it operated on a widget that had already been finalized and returned to the GLib heap. Because OnFileChooserDestroy() accesses the freed dialog (through g_object_set_data() to clear transient-parent properties), this dereference of a dangling pointer is a use-after-free.
The fix reorders the two calls so OnFileChooserDestroy(dialog) runs while the widget is still alive, and only afterward is GtkWindowDestroy(dialog) invoked to free it. The invariant restored is that all accesses to dialog must precede the call that frees it.
GtkWindowDestroy() before the cleanup that still touches it (OnFileChooserDestroy()) had run. The fix simply swaps the order so cleanup completes on the live object before the synchronous free.Attack Path
- Open a native file dialog
A page or renderer-driven flow (e.g. an
<input type="file">interaction) causes the browser process to create a GTK file-chooser dialog tracked inSelectFileDialogLinuxGtk::dialogs_. - Trigger destructor with a live dialog
The
SelectFileDialogLinuxGtkis destroyed while one or more dialogs remain indialogs_, entering the loop that tears each one down. - Free-then-use on the GLib heap
GtkWindowDestroy(dialog)synchronously finalizes and frees the widget, thenOnFileChooserDestroy(dialog)dereferences the freed pointer viag_object_set_data(), reading/writing already-freed GLib heap memory (the use-after-free). - Reclaim the freed allocation
An attacker who can control GLib/browser-process heap allocations between the free and the stale access could place attacker-influenced data in the reclaimed slot so the
g_object_set_data()access corrupts controlled state.(inferred)— the diff shows only the UAF, not any specific reclamation primitive. - Escalate to memory corruption / code execution
Controlled corruption of the freed object could be leveraged toward further memory corruption in the browser process.
(inferred)— no escalation primitive is demonstrated by the patch.
Impact Assessment
SelectFileDialogLinuxGtk is destroyed while dialogs remain tracked. The vendor advisory rates this critical severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.8. The advisory metadata classifies it as a use-after-free in File Input and does not state exploited-in-the-wild status or a severity rating.Changed Functions
| Function | Change | Notes |
|---|---|---|
forui/gtk/select_file_dialog_linux_gtk.cc |
modified |
Files Changed
ui/gtk/select_file_dialog_linux_gtk.cc
Audit Directions
- Free-then-cleanup orderingAudit destructors and teardown loops for a synchronous free (
GtkWindowDestroy,g_object_unref,delete) placed before cleanup callbacks that still dereference the same object; the freeing call must come last. - Synchronous GTK/GLib disposalReview other GTK-integrated code (dialogs, windows, transient-parent handling via
ClearAuraTransientParent/g_object_set_data) whereGtkWindowDestroy()or similar drops the last reference immediately, and confirm no later statement touches the widget. - Widget lifetime in tracked collectionsInspect containers like
dialogs_where objects are iterated and destroyed, ensuring per-element cleanup fully completes on each live element before it is freed and that iterators/references are not used after the free.
Patch
From 0852956e05514f481fb7318d884e3b3a6b48ef79 Mon Sep 17 00:00:00 2001
From: Tom Anderson <thomasanderson@chromium.org>
Date: Mon, 08 Jun 2026 15:41:26 -0700
Subject: [PATCH] [Gtk] Fix Use-After-Free in SelectFileDialogLinuxGtk destructor
In SelectFileDialogLinuxGtk::~SelectFileDialogLinuxGtk(), calling
GtkWindowDestroy(dialog) synchronously disposes and finalizes the dialog
widget before OnFileChooserDestroy() runs. Because
OnFileChooserDestroy() accesses the dialog (specifically inside
ClearAuraTransientParent to clear transient parent properties), this
results in a use-after-free on the GLib heap.
This CL resolves this by running OnFileChooserDestroy() to clear
transient parent metadata before synchronously destroying the GtkWidget
with GtkWindowDestroy().
Fixed: 520157118
Change-Id: I15f8596e17fe54abdae95410066d125d702eb0a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7909293
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1643498}
---
diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc
index adf2a549..9e3390f 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
@@ -207,8 +207,11 @@
}
for (GtkWidget* dialog : dialogs) {
CHECK(dialog);
- GtkWindowDestroy(dialog);
+ // `GtkWindowDestroy()` synchronously drops the only reference and frees
+ // the dialog, so run `OnFileChooserDestroy()` (which calls
+ // `g_object_set_data()` on `dialog`) first to avoid a use-after-free.
OnFileChooserDestroy(dialog);
+ GtkWindowDestroy(dialog);
}
CHECK(dialogs_.empty());
}
Original Bug Report
Browser-Process Use-After-Free in SelectFileDialogLinuxGtk Destructor
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 heap use-after-free (UAF) vulnerability exists in the browser process of Chromium on Linux when using the GTK file chooser dialog. In the destructor of SelectFileDialogLinuxGtk, destroying the GTK widget synchronously frees the object, while a subsequent callback accesses the freed dialog pointer to clear the transient parent data. This results in a use-after-free on the GLib/system heap, bypassing PartitionAlloc and MiraclePtr protections.
Affected files:
ui/gtk/select_file_dialog_linux_gtk.cc
Estimated timestamp from git blame: 2021-03-26
Description
A potential heap Use-After-Free (UAF) vulnerability exists in the GTK file chooser implementation for Linux (ui/gtk/select_file_dialog_linux_gtk.cc). The bug is located in the destructor SelectFileDialogLinuxGtk::~SelectFileDialogLinuxGtk(), where a native GTK widget is synchronously destroyed, followed by an immediate access to the same widget pointer.
In SelectFileDialogLinuxGtk::~SelectFileDialogLinuxGtk():
for (GtkWidget* dialog : dialogs) {
CHECK(dialog);
GtkWindowDestroy(dialog);
OnFileChooserDestroy(dialog);
}
GtkWindowDestroy(dialog)dispatches to eithergtk_window_destroy(GTK4) orgtk_widget_destroy(GTK3). Since Chromium does not hold any additional reference count (org_object_ref) on the dialog, this synchronously triggers the GObject dispose and finalize phases, freeing the memory of theGtkWidgeton the GLib/system heap.- Immediately after,
OnFileChooserDestroy(dialog)is called with the freeddialogpointer. - Inside
OnFileChooserDestroy, ifstate.parent(the native browser window) is non-null, it callsClearAuraTransientParent:
void SelectFileDialogLinuxGtk::OnFileChooserDestroy(GtkWidget* dialog) {
...
if (state.parent) {
CHECK(dialog);
ClearAuraTransientParent(dialog, state.parent, platform_);
state.parent->RemoveObserver(this);
}
...
}
ClearAuraTransientParentexecutesg_object_set_data(G_OBJECT(dialog), kAuraTransientParent, nullptr), which performs aG_IS_OBJECTcheck and dereferences the freeddialogpointer to clear the associated transient parent property on the GObject. This constitutes a Use-After-Free read and write outside of PartitionAlloc (thus unaffected by MiraclePtr/BackupRefPtr).
Potential Attack Scenario / Trigger Steps
Note: These are potential steps based on code analysis; our tooling does not currently have the capability to run a live exploit verification.
- Environment: Linux desktop using GTK where the
org.freedesktop.portal.FileChooserDBus interface is version < 3 or unavailable, forcingSelectFileDialogLinuxPortalto fall back toSelectFileDialogLinuxGtk. - Action: A web page requests a file dialog via
showOpenFilePicker()under a user activation gesture, then immediately triggers a frame navigation (e.g.,location = 'about:blank') shortly after. - Navigation Cancellation: The navigation invalidates the document, causing
WebContentsBasedCancellerto invoke the cancel callback, which callsFileSystemChooser::FileSelectionCanceled()->delete this;. - Destruction Sequence:
~FileSystemChooserinvokesdialog_->ListenerDestroyed(), which resetsfallback_dialog_insideSelectFileDialogLinuxPortal, dropping the last remaining reference toSelectFileDialogLinuxGtk. - UAF Trigger:
~SelectFileDialogLinuxGtk()executes, destroying the dialog withGtkWindowDestroyand subsequently dereferencing it insideOnFileChooserDestroy.
Suggested Fix
To resolve this issue, the lifetime management during destruction should be inverted. OnFileChooserDestroy(dialog) must be called before the widget is destroyed via GtkWindowDestroy(dialog). This ensures that all operations accessing the widget’s properties (such as clearing transient parent associations) are performed while the object’s memory is fully valid.
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
@@ -207,8 +207,8 @@ SelectFileDialogLinuxGtk::~SelectFileDialogLinuxGtk() {
}
for (GtkWidget* dialog : dialogs) {
CHECK(dialog);
- GtkWindowDestroy(dialog);
OnFileChooserDestroy(dialog);
+ GtkWindowDestroy(dialog);
}
CHECK(dialogs_.empty());
}
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.