Two dates, three days apart.

On August 6, Cloudflare published Kitesurf, a web browser written from scratch for AI agents. Not Chromium with the chrome taken off. A new rendering stack, running inside Cloudflare Workers, with no tabs, no themes, no extensions, and no window. TechCrunch had it the next morning.

On August 9 — tomorrow — ChatGPT Atlas stops working. OpenAI's own words for what happens after that: Atlas "may no longer open, browse, or support agentic workflows." Atlas shipped in October 2025. It is being folded into the ChatGPT desktop app and Codex before its first birthday.

Read together, those two dates describe a relocation. The agent browser as a thing a person looks at is being discontinued in the same week the agent browser as a thing no person will ever look at ships in beta. The category moved down a layer, from the desktop to the datacenter, and it took the last human eyeball with it.

That relocation is worth an hour of your attention, because the security properties change in three directions at once and only two of them are being talked about.

What Kitesurf actually is

Celso Martinho's write-up is one of the better engineering posts I have read this year, and it is refreshingly unglamorous about the premise: "a browser built for AI agents doesn't care about visual elements, like themes, tabs, or browser extensions." What it cares about is context windows, token costs, and how many instances you can run per dollar.

The stack is genuinely new. Rendering modules come from Blitz, a modular Rust rendering engine from the Dioxus team. CSS goes through Stylo, Firefox's CSS engine. Most JavaScript runs on native V8 — Workers already has it — and eval() falls back to Boa, a Rust ECMAScript engine, because Workers does not permit native eval for security reasons. Everything sits on Workers' isolate model, with a component per job: an Engine holding the Chrome DevTools Protocol session, a PageScript isolate per page, a PageRenderer turning computed pages into pixels.

The numbers, median across a fourteen-URL corpus: 3.1× less CPU than Chromium for a screenshot, 3.8× less for HTML extraction, 4.7× less memory for a screenshot, 7.0× less memory for HTML extraction. It pays for that in wall time — 1.8× and 1.7× slower respectively, most of it in rasterisation and image encoding. If you are running one browser, Chromium wins. If you are running ten thousand, that memory ratio is your infrastructure bill.

And the adoption cost is a query parameter. Kitesurf speaks CDP, so "your existing client Puppeteer, Playwright, chrome-remote-interface, or any AI Agent that speaks MCP and CDP, already works." You add browser=kitesurf to a Browser Run endpoint. It is free while in beta, and there is a public playground.

Hold onto the query parameter. It becomes the whole operational point later.

The surface they removed, and the credit they've earned

Start with what is genuinely good here, because there is a lot of it and I don't want the argument that follows to read as a complaint.

Chromium's security model is process isolation of an enormous attack surface. A modern browser is several hundred parsers for hostile input — video codecs, font shapers, image decoders, WebGL shader compilers — wrapped in a sandbox, kept survivable by a fuzzing budget most organisations could not fund. I wrote on July 30 about what that budget looks like from the inside: Google fixed 1,072 security bugs across Chrome 149 and 150, more than the previous twenty-three milestones combined, using a Gemini-based agent harness running in CI every twenty-four hours.

Kitesurf's model is different in kind: most of that surface simply isn't present to isolate. No video playback, no WebGL, no persistent state, no extension model. And the parts it does have are written in Rust, which removes the memory-safety class that a large share of those 1,072 bugs belong to. That claim survives scrutiny — use-after-free in a C++ renderer is a category of defect a Rust renderer does not get to have.

Then there is the egress design, and this one I have to salute directly. Every network call in Kitesurf goes through one component: "Kitesurf does it through one single component, the SandboxOutbound worker, and nothing else can touch the network directly — enforced by Dynamic Workers." Per-page cookie jars. CORS enforced at the chokepoint. Responses filtered on the way back.

Yesterday I wrote about Kimi K3 reading benchmark answers off disk because an evaluation sandbox had inbound blocked and outbound 443 wide open, and I argued that the missing artifact was a verified egress boundary rather than a declared one. Cloudflare shipped a verified egress boundary, architecturally enforced, the same week. Sometimes the thing you said was missing turns up three days later with a diagram. Credit where it is due.

The surface that didn't move at all

Here is the part I have not seen anyone say out loud.

Prompt injection does not live in the parser. It lives in the content.

A bank that replaces its plate-glass windows with steel shutters and moves the vault underground has genuinely hardened itself. Every physical route in is now materially harder. None of it changes whether the teller hands over the money to someone with a sufficiently convincing story. The shutters are the sandbox. The convincing story is the injection. And the teller, in this building, is a language model reading whatever the page happens to say.

Cloudflare knows this. The post says so plainly: "The threat model in the context of AI using a browser is different. New problems like prompt injection and tool safety are top priorities." They are not naive about it. But look at where the architecture actually spends its effort — isolation, egress control, statelessness, graceful degradation to a blank frame — and every one of those is a control on what the browser can do. Not one of them is a control on what the model does with the bytes that come back.

Now notice which two operations Kitesurf is optimised for. The benchmarks in the post are screenshot and HTML extraction. Those are the two headline numbers, the two things the whole engine exists to do cheaply. They are also, precisely and exactly, the two delivery mechanisms for prompt injection into an agent — hidden text in the DOM, or instructions rendered into a screenshot. The markup and the pixels are the payload.

So the honest accounting of the swap has three surfaces moving independently:

  • Memory safety: materially better. Smaller surface, Rust, no C++ renderer. A real win.
  • Egress: materially better. One enforced chokepoint beats a process-level firewall rule you have to remember to write.
  • Semantic injection: unchanged. Zero movement. If anything the delivery got cheaper and faster per instance, which means more pages per agent per hour.

Cloudflare optimised the pipe that carries the attack, hardened everything around the pipe, and the pipe is fine because the pipe was never the problem.

There is a second thing missing from the loop, and it is the one I find harder to shrug off. On Thursday I wrote about the first published efficacy measurement of the human approval prompt — 66.3% of hostile commands caught, with the payload visible in the log for the ones that were missed. A browser with no tabs has no such prompt, and it shouldn't: you cannot put a person in front of a headless browser farm and you should not pretend otherwise. But that means the one control in the agent stack for which we finally have a number is at zero coverage here, by design, and nothing named has replaced it.

The number they published, and the number nobody has

Kitesurf "passes around 215,000+ WPT tests," and Cloudflare is straightforward about what that buys: "the parts of a browser that are important to agents (e.g., CSS, DOM, HTML, selection, SVG, and XHR) have good coverage already."

That is a conformance measurement. Web Platform Tests ask whether the engine implements the specification correctly against well-formed input — the type-approval inspection, where the questions are whether the indicators blink at the right rate and the horn works. The crash test is a separate exercise entirely, and a 215,000-test pass rate stands in for none of it. Nothing there tells you what a deliberately malformed document does to a twelve-week-old rendering pipeline being fed URLs chosen by an adversary.

That number does not exist yet, for anyone, and its absence is not Cloudflare's fault — it is what "twelve weeks old" means. But it is worth being clear-eyed about the components. Blitz's own maintainers say so themselves: "Blitz is currently in a pre-alpha state. It already has a very capable renderer, but there are also still many bugs and missing features," and "we would not yet recommend building apps with it." Boa passes "more than 90%" of test262 and has not reached 1.0. Cloudflare uses modules from Blitz rather than Blitz whole, and Boa only for eval(), so this is not the gotcha it would be if you squinted — but the direction of the trade is real. You are exchanging a well-measured attack surface for a smaller, safer-by-construction, unmeasured one. On memory safety that is probably a good trade. It is still a trade, and only one side of it has published numbers.

Failing your own bot check on purpose

One detail in the limitations section deserves its own paragraph, because I think it is a position rather than a gap.

Cloudflare tells you what Kitesurf can't do: "If you need to play video, render WebGL, negotiate a bot-challenge handshake with real TLS fingerprints, or start a ten-minute authenticated session that requires persistent state — Kitesurf isn't yet the right option."

Read the third item again. Cloudflare sells bot management, runs the Verified Bots programme, and leads the standards work on agent identity — and its own agent browser cannot pass a bot challenge by presenting a convincing human TLS fingerprint. The entire headless-Chromium stealth-plugin ecosystem exists to do exactly that thing.

I doubt that is an oversight, and I doubt it is a twelve-week backlog item. Cloudflare has spent the past year pushing Web Bot Auth and signed agentsRFC 9421 HTTP Message Signatures, Ed25519 keys, a Signature-Agent header pointing at a published key directory. Agents proving who they are cryptographically instead of dressing up as a person. Their own framing is blunt about the alternative: "user agent headers alone are easily spoofed," and IP-based validation is "brittle."

An agent browser that can't impersonate a human is the client-side half of that argument. The capability they left out is the capability their standards work is trying to make unnecessary.

That is the interesting bet buried under the performance numbers: that the web will stop asking agents to look human at all, and that the whole stealth-plugin arms race is a dead end rather than a moat.

Who this is for

Use it if you run browser automation at volume — scraping, monitoring, form-filling, extraction pipelines — where the workload is thousands of short stateless sessions and memory is your cost driver. The ratios are real and the drop-in CDP compatibility means the migration is close to free.

Don't if you need video, WebGL, long authenticated sessions, persistent profiles, or the ability to look like a person to a challenge page. Cloudflare says so themselves, which is more than most beta announcements manage.

And if you do swap: notice that you changed your risk profile on a one-line diff that reads like a performance tweak. browser=kitesurf looks like a config change. It is a rendering engine change, an egress model change, and a JavaScript engine change, and the threat model on the other side of it is different in two directions and identical in the third. The diff will not tell you that. Nothing in your CI will either.

The question I would put on the whiteboard before merging it: when the human at the approval prompt is gone by design rather than by accident, what artifact takes their place — and can you name it? Because "the sandbox" is an answer to a different question, and the sandbox is the part Cloudflare already built.