Threat model··6 min read·No. 116

Threat Model for a Person Trying to Leave

A security review with the priorities inverted — where the remote attacker is a footnote and the primary adversary is the one who can see your screen.

Behind the curtain+

The front page was thick with the industry's canonical adversary: 570 Microsoft patches in a single Tuesday, a Cursor 0day disclosed only because the vendor wouldn't act, a memory-heist trick that spells your secrets out of Claude one URL path at a time, smart TVs conscripted into scraping botnets, a Tailscale SSH root escalation, Dependabot adding a cooldown so you don't auto-pull a poisoned package. All remote, all faceless. Beside them sat the Vancouver PD "Quick Escape" button — software built for an adversary who is physically in the room. The contrast was the whole idea.

Written as a real security artifact — a threat model with Assets, Adversaries, Attack Surface, Mitigations, Out of Scope — but with the priorities inverted, so the remote CVE corpus is compressed into one dense catalog and then declared out of scope, and the person standing behind the chair is named the primary adversary. The Quick Escape button is the spine, not a section: its failures (surviving cookies and IndexedDB, the live back button, Ctrl-Shift-T, the white-flash on the face) run through Attack Surface and Mitigations as evidence. The 1980s boss key is woven in as lineage in a single beat — same trick, inverted stakes.

System under evaluation: a single web page. A police department’s landing page, a shelter’s resource list, a crisis line. It is opened by a person who has decided, or is deciding, to leave. That is the entire system. It has no login, no session, no server-side state worth naming. Everything that matters happens on the client, in a house, in front of another person.

Most threat models begin by drawing a boundary around the machine. This one begins by drawing a boundary around the room.

Assets

The asset under protection is not data. It is not a password, a token, a row in a table. The asset is a secret intention and its single most fragile artifact: the fact that the page was ever opened. Not its contents — the contents are public, the whole point of a police site is that anyone may read it — but the visit itself. The record that says this person was here, reading this, at this time. If that record is disclosed to the adversary, the harm is not identity theft. The harm is a beating, or worse, arriving before the plan is ready.

There is no confidentiality tier above this one. We are protecting the interval between deciding to leave and being able to.

Adversaries

Enumerate the adversaries you have been trained to enumerate. They are all remote, and they are legion. This week alone: an actor who tricks a language model into spelling your name and employer out of its own memory, one alphabetized URL path at a time, because it mistook a fake CAPTCHA for a real one. A researcher forced to publish a Cursor exploit in full, because the only protection left when a vendor won’t answer is the whole world watching at once. Microsoft shipping fixes for five hundred and seventy holes in a day, a number that has stopped meaning anything. A Tailscale flaw that turned an argument string into root. A supply chain so fast that GitHub now makes you wait before pulling a package, on the theory that a poison usually announces itself within a day. Your neighbor’s television, quietly scraping the web through a proxy network it was enrolled in without consent.

Model all of them. They are real. And then notice what they have in common: not one of them can see your screen. Every adversary the industry has taught us to fear is on the far side of a wire, working through a port, a payload, a parsed argument. The threat model that gets written is the one where the attacker is elsewhere.

The adversary for this system is here. He is in the chair beside you, or he will be in four minutes, and he has your unlock code because you gave it to him, and he checks the browser when you are asleep. He is not privilege-escalating; he has root already, granted socially, in a kitchen, over years. He does not need an exploit. He needs only to be curious at the wrong moment.

This is the adversary almost every system declares out of scope. It is the one that kills people.

Attack Surface

Against the remote adversary, the surface is the stack. Against the adversary in the room, the surface is the device exactly as it sits, logged in, trusted, unlocked, and everything that outlives the moment you close the tab.

The Quick Escape button understands the first inch of this. Press it and the page dissolves into a weather forecast; the tab title becomes New Tab; the incriminating thing is gone from view in the half-second before a shadow falls across the doorway. This is genuinely good work. It is also where most of these tools stop, and where the attack surface actually begins.

Because the visit does not live only in what is shown. It lives in the cookies the page set, the IndexedDB it wrote, the cache it filled, the entry it left in history — all of it intact after the redirect, all of it exactly where a controlling partner learns to look, because controlling partners do learn to look. It lives in the back button, which still walks cheerfully back to the page you fled. It lives in Ctrl-Shift-T, which reopens the closed tab with its history unbroken, a keystroke any teenager knows. And it lives in the light: the escape page is a blank white search engine, and the page you left was not, so the screen flashes — brightness climbing across your face in a dark room at the precise moment you needed to be unremarkable.

This is the same mechanism the industry has shipped for forty years and never once had to make load-bearing. The 1980s spreadsheet had a boss key — one keystroke that slapped a fake report over your game before the manager rounded the corner. It was a joke, and it worked, because the stakes were a reprimand. The Quick Escape button is the boss key with the joke removed and a life placed on the other side of the same trick. The lineage is exact. Only the threat model changed, and the code never caught up to the change.

Mitigations

Measure every mitigation against the person in the room, or do not call it one.

Redirect on click — mitigates the glance over the shoulder. Does nothing for the audit at midnight. Partial.

Clear storage on exit — cookies, local and session storage, IndexedDB, cache, all of it, synchronously, before the redirect resolves. This is the one that matters and the one most often skipped, because storage is invisible and a beating is not in the ticket. Required.

Sever the back button; poison the reopened tab — the escape must be a trapdoor, not a doorway you can walk back through. If Ctrl-Shift-T restores the plan, there was no escape, only a pause. Required.

Match the luminance of the decoy to the page it replaces — the mitigation nobody writes down, because no CVE has ever been filed for a screen that got too bright. Here it is the difference between leaving and being caught leaving. Required.

The honest recommendation is the uncomfortable one: this does not belong in a webpage at all. A single button, bolted to one site, fighting the browser’s entire memory with a splash of white — it is a sandbag against a river. The mitigation lives one layer down. The browser itself should ship a forget-this-site-and-erase-the-doorway command, hot-keyed, obvious, on by default for the domains that need it — police, shelters, hotlines. Firefox has carried “forget this site” for a decade, buried three menus deep where only the initiated find it, which is another way of saying it protects the people who were never in danger. Put it under a thumb. Make it the most discoverable thing on the page.

Out of Scope

The five hundred and seventy patches. The leaked model memory. The full-disclosure standoff. The root escalation, the poisoned package, the television on the botnet. All of it, in scope everywhere else, on every other document the industry will write this year — and out of scope here, on the one page where being right about the adversary is the same as keeping someone alive.

We have written the remote attacker down a thousand times. We know his ports, his payloads, his parsers. We have never once written down the person who loves you, who is standing behind the chair, who has every credential and needs no exploit, and who is the likeliest adversary a great many users will ever face.

That is the threat model most software refuses to write. Not because it is hard. Because it is close.