CVE-2026-7990
Overview
Background
- `setup.exe` / installer command switches
- the Chrome Windows installer dispatches on command-line switches (
installer::switches::k...) in a longelse ifchain inside the hunk’s enclosing function (not named in the@@header), each branch performing a distinct privileged install action. - `kOnOsUpgrade`
- the
--on-os-upgradeswitch, invoked by the OS/updater after a Windows version upgrade, which callsinstaller::HandleOsUpgradeForBrowserusing the version extracted fromsetup_exe. - `FileVersionInfo` / `base::Version`
- the switch handler reads
setup_exe’sproduct_version()into abase::Versionand only proceeds ifinstalled_version.IsValid(), otherwise loggingDFATALand returningINVALID_STATE_FOR_OPTION. - `InstallStatus` / `exit_code`
- the branch sets
statusand writes*exit_code = InstallUtil::GetInstallReturnCode(status)to report the outcome.
Root Cause Analysis
The patch moves the entire kOnOsUpgrade handling block from near the end of the installer’s switch else if chain to an earlier position, immediately after the preceding kConfigureUserSettings-adjacent branch. The block’s body is byte-for-byte identical before and after; only its ordering relative to the other switch branches changed. Because the chain is a sequence of mutually exclusive else if (cmd_line.HasSwitch(...)) tests, the practical effect is that --on-os-upgrade is now matched and dispatched before the branches that previously preceded it (including the DeleteChromeRegistrationKeys branch shown being removed from the later position). The advisory frames this as insufficient validation of untrusted input in the Updater, implying the prior ordering let on-OS-upgrade input be processed in the wrong state or after a branch with conflicting side effects.
The fix enforces the intended precedence for the OS-upgrade path; the diff itself shows only the reordering and does not add new validation logic.
kOnOsUpgrade branch within the installer’s switch dispatch chain: handling it earlier ensures the on-OS-upgrade command is processed in the correct order rather than behind other branches, and no check inside the branch was altered.Attack Path
- Trigger the installer with `--on-os-upgrade`
The OS-upgrade flow (or a local actor able to invoke
setup.exe) runs the installer with thekOnOsUpgradeswitch after a Windows upgrade. - Hit the mis-ordered dispatch
Pre-patch, the switch was evaluated late in the
else ifchain, so it could be reached only after, or be shadowed/affected by, earlier branch handling under some state. (The exact interfering branch and state are not fully shown in the diff.) - Process on-OS-upgrade input in a wrong state
The handler runs
HandleOsUpgradeForBrowserwith the version parsed fromsetup_exeunder that unintended ordering, which the advisory classifies as insufficient validation of untrusted input. (inferred: the precise mis-state and any resulting corruption are not demonstrated by the diff.) - Mitigation
Reordering makes
--on-os-upgradetake precedence, so it executes in its intended state.
Impact Assessment
setup.exe, a privileged local component), and matches the advisory’s Insufficient validation of untrusted input in Updater at medium severity. Reaching it requires local invocation of the installer with the --on-os-upgrade switch; the diff shows a reordering only and does not itself demonstrate memory corruption, code execution, or privilege escalation, so any such outcome is (inferred). The advisory does not report in-the-wild exploitation.Files Changed
chrome/installer/setup/setup_main.cc
Audit Directions
- Order-sensitive switch dispatchreview long
else if (cmd_line.HasSwitch(...))chains in installer/updater code for branches whose correctness depends on not being shadowed or preceded by other side-effecting branches. - Privileged command-line entry pointsaudit
setup.exeswitch handlers (kOnOsUpgrade,kConfigureUserSettings,kReenableAutoupdates) for assumptions about install state and for validation ofsetup_exe-derived data such asproduct_version(). - State preconditions before privileged actionscheck that handlers calling
HandleOsUpgradeForBrowser-style routines validateinstaller_state/version before acting, independent of where they sit in the dispatch order.
Patch
From 07a07ca1e5230ffcb12a361ed12858b6f80a2f6c Mon Sep 17 00:00:00 2001 From: David Bienvenu <[email protected]> Date: Fri, 03 Apr 2026 13:07:10 -0700 Subject: [PATCH] win installer: reorder handling of on-os-upgrade Bug: 498892267 Change-Id: Ib764cb9c3759fa4993efd9113b29d16d677184cb Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7729007 Reviewed-by: S Ganesh <[email protected]> Commit-Queue: David Bienvenu <[email protected]> Cr-Commit-Position: refs/heads/main@{#1609926} --- diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 8248498..accfea5 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -945,6 +945,21 @@ CreateEulaSentinel(); } } + } else if (cmd_line.HasSwitch(installer::switches::kOnOsUpgrade)) { + installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION; + std::unique_ptr<FileVersionInfo> version_info( + FileVersionInfo::CreateFileVersionInfo(setup_exe)); + const base::Version installed_version( + base::UTF16ToUTF8(version_info->product_version())); + if (installed_version.IsValid()) { + installer::HandleOsUpgradeForBrowser(*installer_state, installed_version, + setup_exe); + status = installer::INSTALL_REPAIRED; + } else { + LOG(DFATAL) << "Failed to extract product version from " + << setup_exe.value(); + } + *exit_code = InstallUtil::GetInstallReturnCode(status); } else if (cmd_line.HasSwitch(installer::switches::kConfigureUserSettings)) { // NOTE: Should the work done here, on kConfigureUserSettings, change: // kActiveSetupVersion in install_worker.cc needs to be increased for Active @@ -1058,21 +1073,6 @@ installer::DeleteChromeRegistrationKeys(*installer_state, HKEY_LOCAL_MACHINE, suffix, &tmp); *exit_code = tmp; - } else if (cmd_line.HasSwitch(installer::switches::kOnOsUpgrade)) { - installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION; - std::unique_ptr<FileVersionInfo> version_info( - FileVersionInfo::CreateFileVersionInfo(setup_exe)); - const base::Version installed_version( - base::UTF16ToUTF8(version_info->product_version())); - if (installed_version.IsValid()) { - installer::HandleOsUpgradeForBrowser(*installer_state, installed_version, - setup_exe); - status = installer::INSTALL_REPAIRED; - } else { - LOG(DFATAL) << "Failed to extract product version from " - << setup_exe.value(); - } - *exit_code = InstallUtil::GetInstallReturnCode(status); } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { // setup.exe has been asked to attempt to reenable updates for Chrome. bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates();
Original Bug Report
Potential Argument Injection in Updater AppCommand leads to SYSTEM EoP
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 security team.
Overview: A potential argument injection vulnerability exists in the Chrome Updater’s handling of the on-os-upgrade AppCommand. An unprivileged user can leverage a SYSTEM-level COM server to inject arbitrary command-line switches into a SYSTEM process. This can lead to a persistent local privilege escalation to SYSTEM.
Affected files:
chrome/updater/win/app_command_runner.ccchrome/updater/app/server/win/com_classes_legacy.ccchrome/installer/setup/install_worker.ccchrome/installer/setup/setup_main.cc
Estimated timestamp from git blame: 2024-12-19
A potential argument injection vulnerability exists in the Chrome Updater on Windows, allowing a standard unprivileged user to escalate privileges to SYSTEM. This occurs due to a combination of insecure command registration, bypassed COM access checks, and switch precedence issues in the installer.
Root Causes
- Unprivileged COM Access: The SYSTEM-scope COM server (
GoogleUpdate3WebSystemClass) can be instantiated by standard interactive users. When thecreateInstalledAppmethod is called inchrome/updater/app/server/win/com_classes_legacy.cc, it hardcodesis_install = false. This bypasses theIsCOMCallerAllowedcheck, which otherwise enforces administrator rights. - Insecure Command Registration: In
chrome/installer/setup/install_worker.cc, theon-os-upgradeAppCommand is registered with a bare positional%1placeholder (cmd_line.AppendArg("%1")). - Verbatim Parameter Substitution: When an AppCommand is executed,
AppCommandRunner::Runusesbase::internal::DoReplaceStringPlaceholdersto substitute%1. Because the parameter is not confined (e.g.,--switch=%1), an attacker can supply a string starting with--that will be parsed as a brand new switch by the child process. - Switch Precedence: In
chrome/installer/setup/setup_main.cc,HandleNonInstallCmdLineOptionsprocesses potentially dangerous switches like--register-chrome-browserand--remove-chrome-registrationbefore the intended--on-os-upgradeswitch.
Potential Attack Steps
Note: These are suggested steps based on static code analysis; our tooling does not yet have the ability to run code to provide a working Proof of Concept.
- As a standard unprivileged user, an attacker executes a script to instantiate the
GoogleUpdate3WebSystemClassCOM object. - The attacker calls
createInstalledAppwith the Chrome AppID to obtain anIAppWebinterface, bypassing admin checks. - The attacker calls
get_command("on-os-upgrade")to retrieve the registered AppCommand object. - The attacker calls
execute()on the command, providing a malicious argument for the first substitution parameter, such as--register-chrome-browser=C:\path\to\evil.exe. - The updater substitutes the
%1placeholder and launchessetup.exeas SYSTEM with the injected switch. setup.exeevaluates the injected--register-chrome-browserswitch, writing the attacker’s executable path to global HKLM registry keys (e.g.,Software\Classes\ChromeHTML\shell\open\command).- The attacker achieves persistent SYSTEM-level code execution triggered whenever any user opens a file or URL associated with Chrome.
Suggested Fix
- Confine the Placeholder: Modify
chrome/installer/setup/install_worker.ccso theon-os-upgradeparameter is explicitly confined to a safe switch format, e.g.,--previous-version=%1instead of a bare%1. - Enforce COM Access Controls: Ensure that sensitive AppCommands are protected by access controls (e.g., re-introducing a
WebAccessiblegate or strictly checking caller privileges for all commands inGoogleUpdate3WebSystemClass). - Review Switch Evaluation Precedence: Ensure
setup_main.ccprioritizes specific action switches (like--on-os-upgrade) in a mutually exclusive or safe manner so that unexpected combinations of switches do not lead to unintended side effects.
Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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.