Medium watch CVSS 7.8 chrome Input Validation 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
7.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in Updater
DescriptionInsufficient validation of untrusted input in Updater
ComponentUpdater
Bug ClassInput Validation
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker498892267
Fix commit07a07ca1e523 (chromium/src) +15/-15
CWECWE-20 (Improper input validation)
CVSS vectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-04-02 (per vendor advisory)
Fix landed2026-04-03 (public git)
Disclosed2026-05-05
Patch gap32 days — fix public in source before the advisory

Background

`setup.exe` / installer command switches
the Chrome Windows installer dispatches on command-line switches (installer::switches::k...) in a long else if chain inside the hunk’s enclosing function (not named in the @@ header), each branch performing a distinct privileged install action.
`kOnOsUpgrade`
the --on-os-upgrade switch, invoked by the OS/updater after a Windows version upgrade, which calls installer::HandleOsUpgradeForBrowser using the version extracted from setup_exe.
`FileVersionInfo` / `base::Version`
the switch handler reads setup_exe’s product_version() into a base::Version and only proceeds if installed_version.IsValid(), otherwise logging DFATAL and returning INVALID_STATE_FOR_OPTION.
`InstallStatus` / `exit_code`
the branch sets status and 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.

Key insight
The single change is the position of the 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

  1. Trigger the installer with `--on-os-upgrade` The OS-upgrade flow (or a local actor able to invoke setup.exe) runs the installer with the kOnOsUpgrade switch after a Windows upgrade.
  2. Hit the mis-ordered dispatch Pre-patch, the switch was evaluated late in the else if chain, 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.)
  3. Process on-OS-upgrade input in a wrong state The handler runs HandleOsUpgradeForBrowser with the version parsed from setup_exe under 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.)
  4. Mitigation Reordering makes --on-os-upgrade take precedence, so it executes in its intended state.

Impact Assessment

The flaw concerns the Windows installer/Updater (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 dispatch
    review 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 points
    audit setup.exe switch handlers (kOnOsUpgrade, kConfigureUserSettings, kReenableAutoupdates) for assumptions about install state and for validation of setup_exe-derived data such as product_version().
  • State preconditions before privileged actions
    check that handlers calling HandleOsUpgradeForBrowser-style routines validate installer_state/version before acting, independent of where they sit in the dispatch order.
From 07a07ca1e5230ffcb12a361ed12858b6f80a2f6c Mon Sep 17 00:00:00 2001
From: David Bienvenu <davidbienvenu@chromium.org>
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 <ganesh@chromium.org>
Commit-Queue: David Bienvenu <davidbienvenu@chromium.org>
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();
Loading diff…

Original Bug Report

reported by vm...@google.com

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.cc
  • chrome/updater/app/server/win/com_classes_legacy.cc
  • chrome/installer/setup/install_worker.cc
  • chrome/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

  1. Unprivileged COM Access: The SYSTEM-scope COM server (GoogleUpdate3WebSystemClass) can be instantiated by standard interactive users. When the createInstalledApp method is called in chrome/updater/app/server/win/com_classes_legacy.cc, it hardcodes is_install = false. This bypasses the IsCOMCallerAllowed check, which otherwise enforces administrator rights.
  2. Insecure Command Registration: In chrome/installer/setup/install_worker.cc, the on-os-upgrade AppCommand is registered with a bare positional %1 placeholder (cmd_line.AppendArg("%1")).
  3. Verbatim Parameter Substitution: When an AppCommand is executed, AppCommandRunner::Run uses base::internal::DoReplaceStringPlaceholders to 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.
  4. Switch Precedence: In chrome/installer/setup/setup_main.cc, HandleNonInstallCmdLineOptions processes potentially dangerous switches like --register-chrome-browser and --remove-chrome-registration before the intended --on-os-upgrade switch.

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.

  1. As a standard unprivileged user, an attacker executes a script to instantiate the GoogleUpdate3WebSystemClass COM object.
  2. The attacker calls createInstalledApp with the Chrome AppID to obtain an IAppWeb interface, bypassing admin checks.
  3. The attacker calls get_command("on-os-upgrade") to retrieve the registered AppCommand object.
  4. 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.
  5. The updater substitutes the %1 placeholder and launches setup.exe as SYSTEM with the injected switch.
  6. setup.exe evaluates the injected --register-chrome-browser switch, writing the attacker’s executable path to global HKLM registry keys (e.g., Software\Classes\ChromeHTML\shell\open\command).
  7. 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.cc so the on-os-upgrade parameter is explicitly confined to a safe switch format, e.g., --previous-version=%1 instead of a bare %1.
  • Enforce COM Access Controls: Ensure that sensitive AppCommands are protected by access controls (e.g., re-introducing a WebAccessible gate or strictly checking caller privileges for all commands in GoogleUpdate3WebSystemClass).
  • Review Switch Evaluation Precedence: Ensure setup_main.cc prioritizes 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.

View on issue tracker