CVE-2026-12034
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifui/gtk/gtk_ui.cc |
modified |
Files Changed
ui/gtk/gtk_ui.ccui/gtk/gtk_ui.hui/qt/qt_shim.cc
Patch
From 48359cc8a62c916d62fae158b5c5d724111d5163 Mon Sep 17 00:00:00 2001 From: Tom Anderson <[email protected]> Date: Wed, 03 Jun 2026 15:29:45 -0700 Subject: [PATCH] Validate and sanitize icon theme names in GTK and Qt backends. An attacker with access to XSETTINGS (such as a compromised GPU process) could publish a path-traversal payload (e.g., ../../../Downloads) for the Net/IconThemeName property. Since GTK joins this property onto standard search paths without relative-path checks, GDK/GTK would resolve lookups to ~/Downloads and invoke unsandboxed host SVG/image parsers (such as librsvg or gdk-pixbuf) on attacker-controlled files. To prevent this: 1. GtkUi now validates and sanitizes `gtk-icon-theme-name`. When GtkUi detects an unsafe theme name (either on startup or via setting change notifications), it automatically resets GtkSettings' icon theme to the standard, safe "hicolor" default theme. 2. Optimized the GTK event-loop handling to return early from OnThemeChanged() when GtkUi::SanitizeIconThemeName() mutates the property, which avoids redundant clearing and rebuilding of UI colors from recursive notify signals. 3. Added defense-in-depth to GetIconForContentType() in both GTK and Qt backends to reject lookups and return a null image if the active theme name is unsafe. Fixed: 519258799 Change-Id: I411d4516cfe365553ef4252d377d630273d5c66d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7896266 Reviewed-by: Lei Zhang <[email protected]> Commit-Queue: Thomas Anderson <[email protected]> Cr-Commit-Position: refs/heads/main@{#1641259} --- diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc index 43dd02ec..2aec6f0 100644 --- a/ui/gtk/gtk_ui.cc +++ b/ui/gtk/gtk_ui.cc @@ -22,6 +22,7 @@ #include "base/containers/flat_map.h" #include "base/debug/leak_annotations.h" #include "base/environment.h" +#include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/logging.h" #include "base/nix/mime_util_xdg.h" @@ -288,6 +289,24 @@ return true; } +bool IsValidIconThemeName(const std::string& theme) { + base::FilePath theme_path(theme); + return !theme.empty() && theme != "." && !theme_path.IsAbsolute() && + !theme_path.ReferencesParent() && theme_path.BaseName() == theme_path; +} + +std::string GetIconThemeName() { + gchar* theme = nullptr; + g_object_get(gtk_settings_get_default(), "gtk-icon-theme-name", &theme, + nullptr); + std::string theme_string; + if (theme) { + theme_string = theme; + g_free(theme); + } + return theme_string; +} + } // namespace GtkUi::GtkUi() : window_frame_actions_() {} @@ -345,6 +364,7 @@ }; GtkSettings* settings = gtk_settings_get_default(); + SanitizeIconThemeName(); connect(settings, "notify::gtk-theme-name", &GtkUi::OnThemeChanged); connect(settings, "notify::gtk-icon-theme-name", &GtkUi::OnThemeChanged); connect(settings, "notify::gtk-application-prefer-dark-theme", @@ -495,6 +515,10 @@ gfx::Image GtkUi::GetIconForContentType(const std::string& content_type, int dip_size, float scale) const { + if (!IsValidIconThemeName(GetIconThemeName())) { + return gfx::Image(); + } + // This call doesn't take a reference. GtkIconTheme* theme = GetDefaultIconTheme(); @@ -772,6 +796,16 @@ return theme_string; } +bool GtkUi::SanitizeIconThemeName() { + std::string theme = GetIconThemeName(); + if (!IsValidIconThemeName(theme)) { + g_object_set(gtk_settings_get_default(), "gtk-icon-theme-name", "hicolor", + nullptr); + return true; + } + return false; +} + int GtkUi::GetCursorThemeSize() { gint size = 0; g_object_get(gtk_settings_get_default(), "gtk-cursor-theme-size", &size, @@ -822,6 +856,9 @@ #endif void GtkUi::OnThemeChanged(GtkSettings* settings, GtkParamSpec* param) { + if (SanitizeIconThemeName()) { + return; // Exit early; modifying the setting re-triggered this function + } colors_.clear(); custom_frame_colors_.clear(); native_frame_colors_.clear(); diff --git a/ui/gtk/gtk_ui.h b/ui/gtk/gtk_ui.h index ecc60166..a5d3bd2c 100644 --- a/ui/gtk/gtk_ui.h +++ b/ui/gtk/gtk_ui.h @@ -117,6 +117,10 @@ void OnThemeChanged(GtkSettings* settings, GtkParamSpec* param); + // Sanitizes the "gtk-icon-theme-name" setting in GtkSettings if it is unsafe. + // Returns true if the setting was modified. + bool SanitizeIconThemeName(); + void OnCursorThemeNameChanged(GtkSettings* settings, GtkParamSpec* param); void OnCursorThemeSizeChanged(GtkSettings* settings, GtkParamSpec* param); diff --git a/ui/qt/qt_shim.cc b/ui/qt/qt_shim.cc index 6a537293..4a9ac537 100644 --- a/ui/qt/qt_shim.cc +++ b/ui/qt/qt_shim.cc @@ -216,6 +216,16 @@ return scale > 0 ? scale : 1.0; } +bool IsValidIconThemeName(const QString& theme) { + if (theme.isEmpty() || theme == "." || theme == "..") { + return false; + } + if (theme.contains('/') || theme.contains('\\') || theme.contains("..")) { + return false; + } + return true; +} + } // namespace QtShim::QtShim(QtInterface::Delegate* delegate, int* argc, char** argv) @@ -275,6 +285,10 @@ Image QtShim::GetIconForContentType(const String& content_type, int size) const { + if (!IsValidIconThemeName(QIcon::themeName())) { + QIcon::setThemeName("hicolor"); + } + QMimeDatabase db; for (const char* mime : {content_type.c_str(), "application/octet-stream"}) { auto mt = db.mimeTypeForName(mime);
Original Bug Report
Sandbox Escape via Path Traversal in GTK/Qt IconThemeName XSETTINGS
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 path-traversal vulnerability exists in how the GTK UI backend handles the XSETTINGS property representing gtk-icon-theme-name. A compromised GPU process on Linux/X11 could manipulate this property to point the icon search path to the user’s download directory. Combined with a compromised renderer capable of downloading files to disk, an attacker could trigger on-demand SVG/image decoding via host libraries like librsvg inside the unsandboxed browser process.
Affected files:
ui/gtk/gtk_ui.ccui/qt/qt_shim.cc
Estimated timestamp from git blame: 2022-05-26
Detailed Writeup
There is a potential sandbox escape chain on Linux/X11 desktop configurations of Chromium where a compromised GPU process and compromised renderer process can cooperatively force the unsandboxed browser process to parse an attacker-controlled SVG/image file using host-level libraries (such as librsvg or gdk-pixbuf).
Root Cause Analysis
Chromium on Linux was previously patched to reject path-traversal characters in the XSETTINGS-delivered cursor theme name (see ui/base/x/x11_cursor_loader.cc:155 and IsValidCursorThemeName). However, the icon-theme property (Net/IconThemeName corresponding to gtk-icon-theme-name) receives no such validation in the browser process’s GtkUi implementation.
In ui/gtk/gtk_ui.cc:347-349, the browser process subscribes directly to setting changes on the default GtkSettings instance:
GtkSettings* settings = gtk_settings_get_default();
connect(settings, "notify::gtk-icon-theme-name", &GtkUi::OnThemeChanged);
Because Chromium does not retrieve, validate, or sanitize the incoming theme name string before it is processed by GDK/GTK, a path-traversal payload (e.g., ../../../Downloads) is accepted. GTK’s icon-theme loader builds the theme search paths via g_build_filename without relative-path checks, resolving the lookup path to ~/Downloads (relative to standard search directories such as ~/.local/share/icons).
Potential Exploitation Steps
Our tooling agent does not currently have the capability to run code to confirm this scenario, but the suggested/potential steps an attacker would follow are:
- Deliver Exploit Files: A compromised renderer triggers two automatic downloads to the user’s standard
~/Downloadsdirectory without prompting:- An
index.themeconfiguration file defining a local icon directory (Directories=.). - A malicious image payload named
application-pdf.svgdesigned to trigger memory corruption in host SVG/image parsing libraries.
- An
- Hijack XSETTINGS: Under Ozone/X11, the sandboxed GPU process retains an active connection to the X server, cloned pre-sandbox in
ui/ozone/platform/x11/ozone_platform_x11.cc:306. A compromised GPU process sends X11 protocol messages over this socket to claim ownership of the_XSETTINGS_S0selection, then sets theNet/IconThemeNameproperty to../../../Downloads. - Trigger Update: GDK inside the unsandboxed browser process automatically receives the XSETTINGS change and updates
gtk-icon-theme-nameto../../../Downloadson the defaultGtkSettingsinstance. - Force On-Demand Parsing: The renderer triggers the download of a dummy PDF (e.g.,
x.pdf). On download completion,DownloadDisplayController::OnUpdatedItem()automatically opens the details bubble (chrome/browser/download/bubble/download_display_controller.cc:185), which callsDownloadBubbleRowView::StartLoadFileIcon()to resolve the icon on the browser process’s UI thread. - Parser Sink Execution:
IconLoader::ReadIcon()invokesGtkUi::GetIconForContentType("application/pdf", ...)inui/gtk/gtk_ui.cc:495. GTK searches for the icon theme, evaluates~/Downloads/index.theme, and invokes the host’sgdk-pixbuf/librsvgparsing libraries on~/Downloads/application-pdf.svginside the unsandboxed browser process, potentially executing arbitrary code outside the sandbox.
Suggested Fix
To prevent this potential vulnerability, Chromium should implement a validation function for gtk-icon-theme-name (analogous to the existing cursor theme validation).
Specifically, before permitting GDK/GTK to process setting notifications or when querying setting values, Chromium should verify that the theme name is a valid basename, does not contain parent-directory references (..), and is not an absolute path. Alternatively, Chromium should sanitize GtkSettings inputs in GtkUi or intercept and reject path-traversing theme values.
Evaluated with Chrome root at commit: 87214e6721f6c34afd9181b80769a24c0c601c50
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.