How we beat Anubis | Blog<br>Back<br>July 11, 2026<br>How we beat Anubis<br>The anti-bot system, not the Egyptian god.<br>GitHub
Why we ran this<br>Anubis is an anti-bot system that stops mass automated scrapers from overwhelming and DDoS’ing websites. One unintended consequence is that the individual agents now crucial to everyday workflows get blocked along with them. Fortress gives those agents the specific fingerprinting support they need to pass, exposed through Claude’s MCP tools and similar interfaces, to democratise agentic access to the web. This report is our benchmark against Anubis.
What Anubis is<br>Anubis is a proof-of-work firewall that guards a large part of open-source infrastructure, including GNOME’s GitLab, Devuan, the FFmpeg tracker, kernel.org, the Arch wiki, Codeberg, and Sourceware. When an incoming request looks like a browser, Anubis returns an interstitial that requires the client to brute-force a nonce until SHA-256(challenge + nonce) begins with a set number of leading zeros. On success it issues a signed cookie valid for about a week and proxies the request to the origin. It works by charging every visit a measurable amount of CPU.<br>This report measures how Fortress, our stealth browser, and Tilion Cloud, the hosted build, perform against Anubis. Two setups are used: four live production deployments, and a local instance swept across every configurable difficulty level. Fortress clears every live deployment, and Tilion Cloud additionally clears the highest difficulty tiers, which it reaches by solving the proof-of-work outside the browser. The sections below describe the mechanism, the measurements, and how to reproduce them.
How the challenge works<br>Anubis charges every client the same way, and it does not inspect the browser. It reads no canvas, WebGL, or TLS signal. Each client receives the same task: compute SHA-256(challenge + nonce) repeatedly until the digest begins with N leading zeros, where N is the configured difficulty. A real browser performs this in a Web Worker and completes it in a second or two at production settings. A client that only reads the returned HTML never executes the challenge script, so it never receives a cookie and never reaches the origin.<br>Fortress completes the challenge the same way a normal browser does. It executes the challenge JavaScript, waits for the solve to finish, and follows the redirect to the origin. This is sufficient to clear any Anubis deployment configured at a difficulty a real site would use, and it requires no Anubis-specific handling.
Live deployments<br>Fortress was run against four production Anubis deployments. A naive client was run alongside it for comparison: a plain HTTP GET carrying a Chrome user-agent and no JavaScript, equivalent to an untuned fetch.<br>SiteNaive (no JS)FortressTilion CloudGNOME GitLabHTTP 4062.1s, 87 KB pageDevuan gitchallenge1.5sFFmpeg tracchallenge27 KB homepageAnubis docschallenge1.3s<br>Fortress cleared all four deployments in single-digit seconds and returned the real page content. The naive client received the challenge interstitial or an outright rejection on every request.
Difficulty scaling<br>Production Anubis runs at low difficulty, because the CPU cost is paid by human visitors as well. To measure the full range, the official Anubis image was run locally in front of a minimal origin, with the difficulty set per level. Each level used one cold solve and a fresh signing key, so no cached cookie could carry a pass down from a lower level.<br>DifficultyHashes expectedFortress (in-browser)Tilion Cloud34,0964.1s4 (Anubis default)65,5363.9s5~1M2.4s6~16.8M12.4s7~268Mtimed out8~4.3Bnever cleared<br>Anubis ships at difficulty 2 to 4, and observed production deployments run at 3 to 5, all within Fortress’s few-second range. The in-browser solver sustains roughly 1.3 million hashes per second and clears through difficulty 6. Difficulty 7 and 8 function only as a stress test: they would hold a human visitor for minutes, and no observed deployment serves them. Tilion Cloud clears these levels as well, by the method described in the next section.
Clearing the top tier out of band<br>The in-browser solver stalls at difficulty 7 because a Web Worker is a slow environment for hashing, not because Anubis detects anything. Anubis does not require the client to compute the solution in the browser. A reading of the v1.26 challenge, the served main.mjs together with the Go source behind it, shows why an external solve is valid. The challenge data is 128 hex characters of crypto/rand output, and it is not an HMAC of the user-agent, IP, or any fingerprint, so the puzzle is not bound to the browser that received it. The server does not rate-check solve time; it records the elapsed milliseconds as a metric and accepts an immediate answer, and an 87-millisecond report was accepted at difficulty 4. Each challenge id is single-use within a 30-minute window, which prevents replay and places no lower bound on solve speed.<br>Because the challenge is...