CVE-2026-13911
Overview
Files Changed
chrome/browser/spellchecker/spellcheck_service.cc
Patch
From 6c7b3e31db1852b83d93d4fb80f94d96a367a4d6 Mon Sep 17 00:00:00 2001 From: Avi Drissman <[email protected]> Date: Wed, 06 May 2026 09:17:58 -0700 Subject: [PATCH] Only send dictionary updates to correct render processes When updating the custom dictionary, only send the updates to render processes that belong to the correct profile. Fixed: 507239830 Change-Id: Ie535a8c98b866bd5349b6df2ace836b86a6a6964 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7812281 Reviewed-by: Chuong Ho <[email protected]> Commit-Queue: Avi Drissman <[email protected]> Cr-Commit-Position: refs/heads/main@{#1626232} --- diff --git a/chrome/browser/spellchecker/spellcheck_service.cc b/chrome/browser/spellchecker/spellcheck_service.cc index ad11f48..3dc2308 100644 --- a/chrome/browser/spellchecker/spellcheck_service.cc +++ b/chrome/browser/spellchecker/spellcheck_service.cc @@ -548,8 +548,12 @@ for (auto it = content::RenderProcessHost::AllHostsIterator(); !it.IsAtEnd(); it.Advance()) { content::RenderProcessHost* process = it.GetCurrentValue(); - if (!process->IsInitializedAndNotDead()) + if (!process->IsInitializedAndNotDead() || + SpellcheckServiceFactory::GetForContext(process->GetBrowserContext()) != + this) { continue; + } + GetSpellCheckerForProcess(process)->CustomDictionaryChanged(additions, deletions); }
Original Bug Report
Cross-profile leak of custom dictionary words via unguarded AllHostsIterator()
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 Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A logic flaw in SpellcheckService causes custom dictionary updates to be broadcast globally to all renderer processes without verifying the profile. This potentially leaks newly added sensitive dictionary words from one profile to renderers belonging to other profiles. An attacker could extract this cross-profile data via a compromised renderer or a spellcheck oracle side-channel.
Affected files:
chrome/browser/spellchecker/spellcheck_service.ccchrome/browser/spellchecker/spellcheck_custom_dictionary.ccchrome/browser/renderer_context_menu/spelling_menu_observer.cc
Estimated timestamp from git blame: 2019-08-01
A potential cross-profile data leak exists in SpellcheckService::OnCustomDictionaryChanged, where custom dictionary additions and deletions are incorrectly broadcast to all active renderer processes across all BrowserContexts, exposing sensitive user data to unrelated profiles.
Initial logic and parameters involving the user interface adding a word to the SpellcheckCustomDictionary, updating the internal structures, and notifying the SpellcheckService via observer callbacks are validated and function as expected.
However, the critical flaw manifests directly in the broadcast phase. In SpellcheckService::OnCustomDictionaryChanged, the code utilizes content::RenderProcessHost::AllHostsIterator() to loop through renderers. It jumps directly to transmitting the plaintext sensitive word via the spellcheck::mojom::SpellChecker::CustomDictionaryChanged Mojo message to every active renderer. There is no verification that the RenderProcessHost belongs to the same BrowserContext as the SpellcheckService. Consequently, words added in a “Personal” profile are immediately synchronized into the renderer state of completely separate profiles (e.g., “Work” or “Guest”).
Potential Attacker Steps (Tooling constrained - no PoC execution)
- An attacker controls a webpage that the victim visits using Profile B.
- The victim, in a separate window using Profile A, adds a sensitive word to their custom spellcheck dictionary.
- The browser process unconditionally broadcasts the
CustomDictionaryChangedMojo IPC containing the plaintext word to the attacker’s renderer process in Profile B. - The attacker extracts the leaked word either by directly reading renderer memory (if the renderer is compromised) or by utilizing a spellcheck oracle side-channel (dynamically probing words to observe if the spellchecker flags them as incorrect).
Suggested Fix
Modify SpellcheckService::OnCustomDictionaryChanged to filter renderers by BrowserContext before dispatching the Mojo message. For example:
content::BrowserContext* service_context = ...; // Get the context associated with this SpellcheckService
for (content::RenderProcessHost::iterator it(
content::RenderProcessHost::AllHostsIterator());
!it.IsAtEnd(); it.Advance()) {
content::RenderProcessHost* process = it.GetCurrentValue();
if (!process->IsInitializedAndNotDead() ||
process->GetBrowserContext() != service_context) {
continue;
}
GetSpellCheckerForProcess(process)->CustomDictionaryChanged(additions, deletions);
}
Evaluated with Chrome root at commit: a1e33f5848218e21d4a16ae2c1bc94e815c30c7f
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.