Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Browser
DescriptionInappropriate implementation in Browser
ComponentBrowser
Bug ClassLogic Error
Tracker520468718
Fix commit26352cb156c8 (chromium/src) +5/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
for
chrome/browser/lifetime/browser_shutdown.cc
modified

Files Changed

  • chrome/browser/lifetime/browser_shutdown.cc
From 26352cb156c8bfe7741a8e69ed0ab4a2b85812b9 Mon Sep 17 00:00:00 2001
From: Greg Thompson <[email protected]>
Date: Thu, 11 Jun 2026 10:11:03 -0700
Subject: [PATCH] Prefix the args with "--" when restarting the browser

For convenience, base::CommandLine::GetArgs() removes the switch
terminator ("--") that separates switches from arguments, if
present. When populating a new command line with argumens from
another, the conservative thing to do is to unconditionally add a
switch terminator before all args whether it's needed or not. This
avoids accidentally treating an arg as a switch in the new command
line.

Fixed: 520468718
Change-Id: I0327fe08a52d21c0c6d641bf64984e73d1d20591
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7918070
Auto-Submit: Greg Thompson <[email protected]>
Commit-Queue: Will Harris <[email protected]>
Reviewed-by: Will Harris <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1645445}
---

diff --git a/chrome/browser/lifetime/browser_shutdown.cc b/chrome/browser/lifetime/browser_shutdown.cc
index 56fae69..2f7b09b 100644
--- a/chrome/browser/lifetime/browser_shutdown.cc
+++ b/chrome/browser/lifetime/browser_shutdown.cc
@@ -304,8 +304,11 @@
 
       case RestartMode::kRestartThisSession:
         // Copy URLs and other arguments to the new command line.
-        for (const auto& arg : old_cl.GetArgs()) {
-          new_cl.AppendArgNative(arg);
+        if (const auto& old_args = old_cl.GetArgs(); !old_args.empty()) {
+          new_cl.AppendArgNative(FILE_PATH_LITERAL("--"));
+          for (const auto& arg : old_args) {
+            new_cl.AppendArgNative(arg);
+          }
         }
         break;
     }
Loading diff…

Original Bug Report

reported by [email protected]

Potential App-Bound Encryption bypass via dropped command-line terminator during relaunch

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: During a browser relaunch via RestartMode::kRestartThisSession, Chrome reconstructs the child command line but fails to re-insert the ‘–’ switch terminator. Consequently, any slash-prefixed loose arguments can be re-parsed as switches in the child process. This presents a potential mechanism to bypass command-line switch verification, such as that used by the App-Bound Encryption isolation service.

Affected files:

  • chrome/browser/lifetime/browser_shutdown.cc

Estimated timestamp from git blame: 2019-08-23

Description

A potential command-line injection vulnerability has been identified via static analysis in Chrome’s session restart logic on Windows.

When Chrome performs a session relaunch (such as during a downgrade snapshot restore or other scenarios triggering RestartMode::kRestartThisSession), the browser-side relaunch logic reconstructs the command line for the new process by copying arguments from the parent process. However, it does not preserve or re-insert the -- command-line switch terminator.

Root Cause Analysis

In chrome/browser/lifetime/browser_shutdown.cc:

case RestartMode::kRestartThisSession:
  // Copy URLs and other arguments to the new command line.
  for (const auto& arg : old_cl.GetArgs()) {
    new_cl.AppendArgNative(arg);
  }
  break;

When calling old_cl.GetArgs(), base::CommandLine strips out the first instance of the switch terminator (--):

// base/command_line.cc
CommandLine::StringVector CommandLine::GetArgs() const {
  StringVector args(argv_.begin() + begin_args_, argv_.end());
  auto switch_terminator = std::ranges::find(args, kSwitchTerminator);
  if (switch_terminator != args.end()) {
    args.erase(switch_terminator); // "--" is removed
  }
  return args;
}

Since browser_shutdown.cc never re-inserts L"--" prior to appending these arguments, they are written directly to new_cl.argv_.

During process creation via base::LaunchProcess, the command line is serialized using GetArgumentsString(). On Windows, command-line arguments starting with a slash (/) are parsed as switches unless they are preceded by a -- terminator. Because the terminator was stripped and not re-inserted, arguments like /gpu-launcher=C:\a\e.exe or /no-sandbox are serialized and then re-parsed by the child process as active command-line switches.

Potential Attack Scenario / Exploit Path

An attacker with local medium-integrity access could potentially exploit this on enterprise-managed Windows hosts to run arbitrary code under the privileged App-Bound Encryption (ABE) isolation token:

  1. Setup State: The attacker writes a fake higher version string (e.g., 999.0.0.0) to %LOCALAPPDATA%\Google\Chrome\User Data\Last Version and sets up a mock snapshot directory to trigger a downgrade-and-relaunch flow.
  2. COM Elevation Trigger: The attacker calls IElevator2::RunIsolatedChrome passing the payload arguments safely positioned after a switch terminator, for example: chrome.exe -- /gpu-launcher=C:\a\e.exe /no-sandbox.
  3. First Hop Safety: The elevation service correctly filters switches and appends -- to ensure the payload arguments remain treated as arguments (hop 1 is secure).
  4. Relaunch Bug Trigger: During startup, Chrome detects the pending downgrade and triggers a relaunch using RestartMode::kRestartThisSession. During this reconstruction, the -- terminator is dropped.
  5. Second Hop Launch: The child process is spawned via plain CreateProcess (inheriting the elevated isolation token carrying the GOOGLECHROME://ISOLATION security attribute). The child re-parses /gpu-launcher as an active switch, executing the attacker’s wrapper e.exe inside the privileged isolation context. This allows the attacker to query IElevator::DecryptData and bypass App-Bound Encryption.

Note: These are potential steps derived from code analysis; our tooling does not currently support running live exploit validation.

Proposed Fix

In chrome/browser/lifetime/browser_shutdown.cc, when copying arguments under RestartMode::kRestartThisSession, ensure that if old_cl.GetArgs() is not empty, the switch terminator -- is appended to the command line before adding the individual arguments:

case RestartMode::kRestartThisSession:
  if (!old_cl.GetArgs().empty()) {
    new_cl.AppendArgNative(FILE_PATH_LITERAL("--"));
    for (const auto& arg : old_cl.GetArgs()) {
      new_cl.AppendArgNative(arg);
    }
  }
  break;

Evaluated with Chrome root at commit: e9507a33bb4148ee071aaaf8a7e9ad68770359bf


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.

View on issue tracker