CVE-2026-113060
Overview
Fix not yet public
Original Bug Report
UI spoofing in Bluetooth pairing prompts via unsanitized device names
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: Bluetooth device names containing Unicode BiDi control characters or newlines are rendered unsanitized in pairing notifications and dialogs. An attacker in RF range can spoof trusted device names or inject misleading text to trick users into accepting unauthorized pairing requests. This can lead to malicious device bonding and potential keystroke injection attacks.
Affected files:
ash/system/bluetooth/bluetooth_notification_controller.ccchrome/browser/ui/views/bluetooth_device_pair_confirm_view.ccdevice/bluetooth/bluetooth_device.ccdevice/bluetooth/string_util_icu.cc
Estimated timestamp from git blame: Unknown (Google3 checkout)
Summary
Potential UI spoofing vulnerabilities exist in the Bluetooth pairing flow on ChromeOS and cross-platform Chrome. Bluetooth device names (GAP names) provided by remote devices are rendered in security-sensitive pairing prompts without adequate sanitization. By incorporating Unicode Bidirectional (BiDi) control characters or newlines, a malicious device can misrepresent its identity or inject fake status indicators into the pairing UI.
Root Cause Analysis
The issue originates in device/bluetooth/bluetooth_device.cc. The method BluetoothDevice::GetNameForDisplay() retrieves the remote device name and, after a minimal check for graphic characters, returns it as an unsanitized UTF-16 string.
// device/bluetooth/bluetooth_device.cc
std::u16string BluetoothDevice::GetNameForDisplay() const {
std::optional<std::string> name = GetName();
if (name && HasGraphicCharacter(name.value())) {
return base::UTF8ToUTF16(name.value()); // Unsanitized return
} else {
return GetAddressWithLocalizedDeviceTypeName();
}
}
The HasGraphicCharacter() check (in device/bluetooth/string_util_icu.cc) only ensures the string contains at least one printable character; it does not remove control characters like Right-to-Left Override (RLO, U+202E) or newlines (U+000A).
Vulnerability Details
1. BiDi Spoofing
When the unsanitized name is passed to a views::Label, the rendering engine (via gfx::RenderText) respects Unicode BiDi formatting. An attacker can use RLO to reverse the appearance of the device name. For example, a name advertised as \u202EsyeK XM hcetigoL will be rendered as “Logitech MX Keys”, allowing the attacker to impersonate trusted hardware brands.
2. Newline Injection
In both ChromeOS pairing notifications (ash/system/bluetooth/bluetooth_notification_controller.cc) and the cross-platform pairing dialog (chrome/browser/ui/views/bluetooth_device_pair_confirm_view.cc), the device name is rendered in a multi-line views::Label. An attacker can inject a newline character (\n) followed by convincing instructional text, such as “Verified by System” or “Secure Connection”, to deceive the user.
Impact
A successful spoofing attack can trick a user into approving a pairing request from a malicious device. If the attacker’s device presents a Human Interface Device (HID) profile (e.g., a keyboard), the attacker gains the ability to inject arbitrary keystrokes into the user’s session once the bonding is established, potentially leading to full system compromise.
Potential Reproduction Steps
- Use a Bluetooth-capable host (e.g., a Linux machine with BlueZ) to advertise a malicious GAP name:
- BiDi spoof:
hciconfig hci0 name $'\u202EsyeK XM hcetigoL' - Newline injection:
hciconfig hci0 name $'Malicious Device\nVerified by ChromeOS'
- BiDi spoof:
- Configure the host to use a Keyboard device class and
DisplayYesNoIO capabilities. - Initiate pairing from the malicious host to a target Chromebook or a machine running Chrome.
- Observe the resulting pairing notification or dialog on the victim’s device, noting the spoofed name or injected text.
Suggested Fix
Device names should be sanitized before being returned by GetNameForDisplay() or before being passed to UI components. Recommended actions include:
- Collapsing or replacing all control characters and newlines with spaces.
- Stripping or isolating BiDi control characters using
base::i18n::SanitizeUserSuppliedString()or wrapping the name in BiDi isolation characters (FSI/PDI).
Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a
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.
Raised in root component due to access or custom field issues on 1131776