CVE-2026-11677
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifservices/network/public/cpp/simple_url_loader.cc |
modified |
Files Changed
services/network/public/cpp/simple_url_loader.cc
Patch
From 037c5ddb3336e88e3215f9e2cb903282d032b653 Mon Sep 17 00:00:00 2001 From: Kenichi Ishibashi <[email protected]> Date: Tue, 02 Jun 2026 20:42:51 -0700 Subject: [PATCH] Improve temporary file creation and error handling in SimpleURLLoader This CL updates SimpleURLLoader to use base::CreateAndOpenTemporaryFileInDir() when downloading to a temporary file. This atomically creates and opens the file, retaining the file descriptor directly and avoiding the previous pattern of closing and re-opening the file by path. Additionally, it improves error reporting on initialization failure by explicitly mapping base::File::error_details() to a net::Error via net::FileErrorToNetError(). Bug: 516979551 Change-Id: I353bac993212cbee76cb8a1c3c086e73ff4e6369 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7885361 Reviewed-by: mmenke <[email protected]> Commit-Queue: Kenichi Ishibashi <[email protected]> Cr-Commit-Position: refs/heads/main@{#1640681} --- diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc index 23e127d..1ac2f96 100644 --- a/services/network/public/cpp/simple_url_loader.cc +++ b/services/network/public/cpp/simple_url_loader.cc @@ -1020,28 +1020,28 @@ DCHECK(!file_.IsValid()); DCHECK(!body_reader_); - bool have_path = !create_temp_file_; - if (!have_path) { - DCHECK(create_temp_file_); - have_path = base::CreateTemporaryFile(&path_); - // CreateTemporaryFile() creates an empty file. - if (have_path) - owns_file_ = true; - } - - if (have_path) { - // Try to initialize |file_|, creating the file if needed. + if (create_temp_file_) { + base::FilePath temp_dir; + if (base::GetTempDir(&temp_dir)) { + file_ = base::CreateAndOpenTemporaryFileInDir(temp_dir, &path_); + } + } else { file_.Initialize( path_, base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS); } // If CreateTemporaryFile() or File::Initialize() failed, report failure. if (!file_.IsValid()) { + net::Error net_error = net::FileErrorToNetError(file_.error_details()); + if (net_error == net::OK) { + net_error = net::MapSystemError(logging::GetLastSystemErrorCode()); + if (net_error == net::OK) { + net_error = net::ERR_FILE_NOT_FOUND; + } + } body_handler_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(on_done_callback), - net::MapSystemError( - logging::GetLastSystemErrorCode()), - 0, base::FilePath())); + FROM_HERE, base::BindOnce(std::move(on_done_callback), net_error, 0, + base::FilePath())); return; }
Original Bug Report
Potential macOS sandbox escape via TOCTOU in SimpleURLLoader temporary file creation
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 Time-of-Check to Time-of-Use (TOCTOU) vulnerability exists in SimpleURLLoader’s temporary file creation mechanism on macOS. A compromised, sandboxed network service process can exploit a race condition in the shared temporary directory to swap a temporary file with a symbolic link. Because the browser process re-opens the file path without symbolic link protection, it may follow the link and overwrite arbitrary files with browser process privileges.
Affected files:
services/network/public/cpp/simple_url_loader.cc
Estimated timestamp from git blame: 2017-10-18
Summary
A potential Time-of-Check to Time-of-Use (TOCTOU) vulnerability has been identified in the temporary file writing logic of SimpleURLLoader (services/network/public/cpp/simple_url_loader.cc). When downloading to a temporary file, the code generates and closes a temporary file, and subsequently re-opens the path. On macOS, both the unsandboxed browser process and the sandboxed network service process share access to the same temporary directory, creating a race window where a compromised network service can replace the temporary file with a symbolic link, resulting in an arbitrary file write under browser privileges (sandbox escape).
Vulnerability Analysis
In services/network/public/cpp/simple_url_loader.cc, within FileWriter::StartWritingOnFileSequence (lines 1023-1036):
bool have_path = !create_temp_file_;
if (!have_path) {
DCHECK(create_temp_file_);
have_path = base::CreateTemporaryFile(&path_); // (1) Creates the file and immediately closes its file descriptor
if (have_path)
owns_file_ = true;
}
if (have_path) {
file_.Initialize(
path_, base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS);
// (2) Re-opens the file by path
}
-
Step 1 (
base::CreateTemporaryFile): The helperbase::CreateTemporaryFile(defined inbase/files/file_util.cc, line 395) resolves the temporary directory and callsmkstempviaCreateAndOpenFdForTemporaryFileInDir. It immediately closes the returned file descriptor, leaving only the generated path string inpath_(e.g.,/private/var/folders/.../T/.com.google.Chrome.XXXXXX). -
Step 2 (
file_.Initialize): The browser process re-opens this path on a background thread usingfile_.Initializewithbase::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS. On POSIX platforms (including macOS),FLAG_CREATE_ALWAYSmaps directly toO_CREAT | O_TRUNC(inbase/files/file_posix.cc, lines 573-577). Crucially, the flag map does not employO_NOFOLLOWor check whether the target is a symbolic link.
Sandbox Context (macOS)
Although the Network Service is sandboxed, its macOS Seatbelt profile (sandbox/policy/mac/network.sb, lines 50-53) explicitly permits read and write access to the per-user temporary directory:
(allow file-read* file-write*
(subpath (param darwin-user-cache-dir))
(subpath (param darwin-user-temp-dir))
)
The parameter darwin-user-temp-dir is retrieved in the browser process via confstr(_CS_DARWIN_USER_TEMP_DIR, ...) and passed during the launching of the child process. Therefore, both the unsandboxed browser process (running SimpleURLLoader’s file sequence) and the sandboxed network process share access to the exact same temporary directory path.
Potential Exploitation Scenario
Based on static analysis, a compromised network process could potentially execute the following steps to escape the sandbox:
- Monitoring: The compromised network process monitors the
darwin-user-temp-dirfor the creation of temporary files adhering to the pattern.com.google.Chrome.XXXXXX. - The Race: Immediately after
base::CreateTemporaryFileis called and closes its file descriptor (Step 1), but before the browser process callsfile_.Initialize(Step 2), the attacker deletes the empty temporary file viaunlink(). - Symlink Placement: The attacker creates a symbolic link at that exact path pointing to a highly sensitive destination in the user’s home directory (e.g.,
~/Library/LaunchAgents/persistence.plistor~/.zshrc). - Overwrite: When the browser process calls
file_.Initialize, theopencall follows the symbolic link, truncating the targeted plist or shell script, and writes the incoming network payload directly into it. - Retry Mitigation: If the attacker misses the tight race window, they can abort the loader from the network side with
net::ERR_NETWORK_CHANGED. This triggersSimpleURLLoader’s retry mechanism (frequently used by components like theExtensionDownloader), giving the attacker multiple attempts to win the race.
Note: These are potential/suggested exploitation steps derived from static code and sandbox profile tracing, as our current tooling does not have the capability to execute code or verify runtime behavior.
Suggested Fix
Avoid closing and re-opening the file by path. Instead of calling base::CreateTemporaryFile and then file_.Initialize, utilize an API that keeps the file descriptor open upon creation, such as base::CreateAndOpenTemporaryFileInDir. This ensures that the browser retains exclusive and safe access to the file handle created atomically by mkstemp without leaving a path open to TOCTOU manipulation.
Evaluated with Chrome root at commit: b1520ef4a76878853a31f0943b565e42060edec8
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.