June 30, 2026
I let strangers run any code on the page. They still couldn’t delete the warning on it.
Originally published on LinkedIn.

By Armen
3 min read
I let strangers run any code on the page. They still couldn't delete the warning on it.
Originally published on LinkedIn.
I hand strangers a real website with full admin. The hard part wasn't handing it over — it was the warning label they're not allowed to peel off.
The whole point of wp.run is that the site is yours. Click once and you get a real WordPress install on a real public subdomain, with the real admin password. Install any plugin, paste any PHP, run any JavaScript. You're root inside your own two-hour box.
Which is exactly the problem. Some of those boxes become phishing pages and fake checkouts, so every visitor has to see the same thing first: a full-screen warning that this is an anonymous sandbox, not the brand it's dressed up as, and not a place to type a password. A warning the site's owner cannot take down.
Sit with that. It's their site. Their code runs on every request. Any banner I inject is a <div> they can delete — one line in functions.php, one display:none, and my warning is gone on exactly the pages that need it most. I can't win a fight that happens inside WordPress, because inside WordPress, the attacker writes the rules.
So I stopped trying to win it there.
The warning lives one floor up
It lives in the proxy, not the website. Every sandbox sits behind Traefik, and before Traefik forwards a single byte to a container, it asks a small gatekeeper one question: is this visitor cleared? If not, Traefik serves the gatekeeper's answer — the warning page — and WordPress never runs for that request at all. There's nothing for a plugin to override, because the plugin's code is on the far side of a door that hasn't opened yet.
The gate is deliberately narrow. It stops exactly one thing: a page a human is about to look at. Navigate to the site and you hit it. Try to bury the phish in an <iframe> and you hit it there too — the warning refuses to render in a frame anyway. Everything else — CSS, JavaScript, images, REST calls — sails straight through. Click Continue once and the real site works instantly. The warning is unmissable and nearly invisible at the same time.
The trick is telling a page view from everything else without trusting anything the attacker authors. The gate doesn't read the filename — a phishing page called login.css proves nothing. It reads the browser's own declaration of intent: the Sec-Fetch-Dest header, which the browser sets and JavaScript can't forge. When that signal is missing it falls back to weaker hints, and when it still can't tell, it shows the warning. It fails toward the warning, never away from it.
It worked. And then I noticed it didn't.
The link that skipped the unskippable warning
The first version of Continue was a query parameter: ?_wprun_continue=1. Click the button, the gate sees the 1, drops a cookie, lets you in. Clean. Obvious. Broken.
Because 1 is a constant. Anyone can type it.
An attacker doesn't have to defeat the warning — they route the victim around it. They mail https://fake-bank.wprun.site/?_wprun_continue=1, the victim clicks, and the gate drops them straight onto the phishing page. No warning. The one promise the design existed to make — follow a link, see the warning first — came undone with a single character in a URL.
The skip token, it turns out, was a credential. And I'd set every site's password to 1.
The tempting reading is the secret was too weak — make it long and random. But a long random constant is still a constant. The real problem is who writes the token into the victim's request. The URL is authored by whoever sends the link, so the attacker never has to guess the secret — they set it. Hold the link, hold the key.
So the proof moved out of the URL into a channel the attacker can't write to. Every warning page mints a fresh random nonce, stores it in a SameSite=Strict, HttpOnly cookie pinned to that one subdomain, and embeds the same nonce in its Continue link. The gate opens only when the two match. The attacker can put any token they like in a URL, but they can't read the cookie, can't write it, and can't borrow the victim's across a cross-site click. The crafted link is inert.
The fix was never a stronger secret. It was changing who's allowed to speak.
The label still can't be peeled off. Now it can't be walked around either.