Forty lines freeze your Mac
How the Deathray technique lets an untrusted website freeze an entire Mac by overloading WindowServer, why the browser sandbox can't stop it, and what to do.
A single web page, maybe 40 lines of JavaScript and CSS, can lock up a Mac so hard that the cursor stops moving and the only way out is holding the power button. No exploit of a memory bug. No malware install. No permission prompt. The tab loads, the machine stops responding, and the person watching it happen assumes their hardware finally died.
That technique has a nickname in the corners of the security world: the Deathray. It is not a single vulnerability with a patch number waiting for it. It is a category of resource-exhaustion attack that works because of how macOS draws things on screen, and it keeps coming back in slightly different clothes every couple of years.
What actually freezes - it isn’t the browser
The detail most write-ups get wrong: the browser tab is not the thing that dies. WindowServer is.
Every pixel you see on a Mac is composited by a single system process called WindowServer. It runs outside your browser, outside your apps, at the level of the login session. When Safari or Chrome wants to put something on screen, it hands the drawing work to WindowServer. That process is shared by every application on the machine, and in practical terms it is a serialization point. If it gets stuck on one enormous drawing job, everything queued behind it - your dock, your menu bar, your other windows, the beachball watchdog itself - waits too.
So the attack does not try to crash the browser. It feeds the browser cheap instructions that translate into absurdly expensive compositing work, and lets WindowServer strangle itself. The tab is the delivery mechanism. The graphics layer everyone shares is the target.
That is why “just force-quit the browser” does not save you. By the time the freeze lands, the process you would need to click on can’t be clicked, because the thing that draws the click is the thing that’s jammed.
The mechanism, in plain terms
The recipe is boring, which is the point. You take an operation that is cheap for a web page to request and expensive for the system to render, and you request it at scale.
The ingredient list, all of which has shown up in real freeze pages over the years:
- Tens of thousands of stacked DOM elements, each with a CSS backdrop filter or blur applied, forcing the compositor to blend layer on layer on layer.
- Enormous SVG filter chains - a
feGaussianBlurfeeding afeDisplacementMapon a canvas scaled to something like 8000 by 8000 - where a two-line filter expands into billions of per-pixel operations. - A CSS animation set to run every frame on a property that can’t be GPU-accelerated, so the machine tries to recomposite the whole tree 60 times a second and never finishes a single pass.
window.openorhistory.pushStateloops that spawn drawing work faster than it can drain.
None of these are bugs in the sense of a coding mistake. Each individual instruction is legal. The page is allowed to ask for a blur. It is allowed to ask for ten thousand of them. The specification never said “and if you ask for too many, the process that draws every other app on the computer should also stop.” That unstated assumption is the vulnerability.
Why the browser sandbox doesn’t help
People assume the browser sandbox contains this. The sandbox is real and it is good at what it was built for: stopping a malicious page from reading your files, your other tabs, or your memory. It draws a hard line around what a page can touch.
It draws almost no line around what a page can ask for. Requesting a giant blur is not a security violation - it is a normal rendering request, the same call a legitimate photo-editing web app makes. The sandbox has no clean way to tell “this site wants a nice frosted-glass effect” apart from “this site wants to jam the compositor,” because they are the same API call at different magnitudes.
This is the general shape of every denial-of-service problem. The malicious input is indistinguishable from heavy legitimate input until you measure the cost, and by the time you’ve measured it you’ve already paid it. The sandbox protects confidentiality. It does close to nothing for availability.
Why Macs specifically
This runs on other systems too, but it bites Macs harder for a structural reason: the degree of shared, single-path compositing.
On a Mac, WindowServer is a chokepoint by design. That design buys you the smooth, consistent animation Apple is known for, because one authority owns the screen and schedules everything coherently. The price of that coherence is shared fate. Overload the one scheduler and the coherence becomes a single point of failure for the entire graphical session.
There is a second aggravating factor: recovery is weak. On many Linux setups you can drop to a text console with Ctrl-Alt-F-key and kill the offending process, because the compositor and the input path are not the same thing. macOS gives a general user no equivalent escape hatch. There is no “get me a terminal that isn’t drawn by the frozen process” for someone who isn’t already living in SSH. The realistic recovery is a hard power cycle, which means unsaved work in every open app is gone - not just the browser’s.
Telling it apart from a dying machine
The reason this technique launders itself as hardware failure is that the symptoms overlap exactly with the ones people already fear. Beachball cursor, fans spinning to maximum, the case hot to the touch, total input lockup - that is also what a failing SSD or a swap-thrashing memory leak looks like.
The tell is timing and repeatability. It happens right after a specific page loads, it happens again if you load that same page, and the machine is completely fine on every other site. A hardware fault does not politely wait for one URL. If a freeze tracks a link, it is the link.
Why this is a real problem and not a party trick
The instinct is to file this under “annoying, not dangerous.” Nobody stole data. Nothing was installed. You rebooted and moved on. That instinct undercounts three real costs.
First, it is a delivery-neutral trigger. The freeze page needs no download and no “allow” click. It needs you to load a URL. That means it fits inside anything that renders a URL you didn’t choose: a malicious ad in a legitimate ad network, an <iframe> on a compromised site, a link preview, a page opened by an email client’s built-in browser. A wave of freeze-ads pushed through a real ad exchange reads to victims as “my Mac has been flaky lately,” not “I was attacked.”
Second, availability is a security property. For someone doing live work - a trader mid-order, a broadcaster on air, a clinician reading imaging, a support engineer on a call - a reliable “freeze this machine on demand from a link I can get you to open” is a functional weapon, even with zero data theft. Ransomware’s entire business model is denying availability. This denies it for free, without persistence, which also means without the forensic trail persistence leaves behind.
Third, it is cheap to weaponize and expensive to attribute. There is no payload to reverse-engineer, no command-and-control server to trace, no binary sitting on disk. Afterward there is a rebooted Mac and a browser-history entry the user has probably already cleared out of embarrassment.
What you can actually do
For a regular Mac user, the honest mitigations are thin, and I would rather say that plainly than pretend there is a switch that fixes it.
- Save constantly and favor apps that auto-save. Your realistic recovery is a hard reboot, and everything unsaved dies with it. This is the single highest-value habit.
- Run a content blocker that strips third-party ads and scripts. It does not patch the technique; it removes the most likely delivery channel, which is a hostile ad rendering inside a site you trusted.
- Keep macOS and your browser current. Apple and browser vendors periodically add caps - limits on filter-region size, on layer counts, on per-frame compositing budget - that turn a full freeze into a slow tab or a killed page. These are ceilings, not cures; the next variant routes around the last cap.
- If it happens, hold the power button, reboot, and do not reopen the tab from history. That is the whole playbook. There is no “clean it off the machine” step, because nothing was left on the machine.
For developers and platform people, the durable fix is not another blocklist. It is cost accounting at the compositor: the layer that renders untrusted content has to treat drawing work as a metered, cancellable resource, with per-origin budgets and a way to abort a frame that blows past its budget instead of blocking the shared server on it. Until the expensive request can be priced and refused mid-flight, the same class of page keeps coming back wearing a different filter.
The Deathray is worth understanding precisely because it is dull. There is no clever memory corruption, no zero-day aura. It is a plain observation that we built the fast, pretty parts of our computers on one shared resource, handed untrusted web pages a straw into that resource, and never fully priced what they are allowed to drink.
Keep Reading
privacyChrome exempts Google's domains from user site-data controls
Chrome does not enforce user site data settings against Google-owned domains. What the exempt scope means and how to treat the control.
systems driftYour browser obeys someone else
Chrome disabling uBlock Origin was not a vendor choice to escape but a structure to see: software resolved by reference, executed without revalidating trust.
browser securityYour VPN extension trusts every website you visit
A hardcoded trigger word in a million-install Chrome VPN extension let any website disable the tunnel, change exit nodes, and read open tabs.
Stay in the loop
New writing delivered when it's ready. No schedule, no spam.