Anubis proof of work: how the AI scraper challenge works

How Anubis proof of work runs: the SHA-256 puzzle, the week-long cookie bound to your IP, weights by country and ASN, its limits, and where proxies fit.

Beside your browser, a tray of SHA-256 tries worked in the browser: gold dice, one green reading 0000. The route runs from the browser to the Anubis gate, set to difficulty 4, which holds the pass it issued: a signed cookie, 7 days, bound to your IP, and on to the site.
Quick summary · TL;DR
  1. Anubis makes the browser pay a small hash cost before a page loads. It must find a nonce whose SHA-256 hash with a random server string starts with a set number of zeros; the server checks the answer with one hash.
  2. One pass lasts a week from one IP. The signed cookie expires after seven days by default and is bound to the client address and to the policy rule that issued it.
  3. Weights pick the difficulty. A browser User-Agent, a weighted country or a weighted cloud network each add points, and thresholds turn the total into allow, meta refresh or a proof of work of difficulty 2, 4 or 6.
  4. Proof of work prices access and does not prove identity. Native solvers and real browsers pass it, so the project now adds ASN weights, memory-hard puzzles and headless detection.

Anubis proof of work is the challenge the open-source Anubis reverse proxy shows before a protected site loads. The browser searches for a number that, hashed with SHA-256 together with a random server string, starts with a set count of zeros. One success earns a signed cookie, valid for a week by default and tied to the visitor’s IP.

The page with the jackal mascot now sits in front of code forges, bug trackers, wikis and library catalogues. Visitors meet it as a progress bar. Site operators meet it as a policy file. Crawler and test-rig owners meet it as a page that returns HTTP 200, holds no content and comes back every time the client’s IP address changes.

What Anubis proof of work is

Anubis is a web application firewall written in Go by Xe Iaso and maintained by Techaro, released under an MIT-style licence. It runs as a reverse proxy: requests reach Anubis first, and only clients that pass its rules reach the real site. As of October 2026, the current stable release is v1.27.0, tagged on August 8, 2026, with v1.28.0 in pre-release since August 30, 2026.

Anubis proof of work borrows from Hashcash, the anti-spam stamp idea Anubis’s own design notes (read October 3, 2026) credit as the inspiration. A single visitor pays a small computing cost once. A crawler fetching a hundred thousand pages from many addresses pays it again and again.

Those notes are candid about the limit. They call the proof of work “a hack whose real purpose is to give a ‘good enough’ placeholder” while the project builds better ways to tell headless browsers from people.

How the challenge works

The flow, per the how Anubis works page, runs in five steps:

  1. A request matches a rule that says CHALLENGE. Anubis stores a challenge record (64 random bytes, the difficulty, the rule that matched, and the request’s User-Agent and IP) for 30 minutes.
  2. The page’s JavaScript spawns Web Workers, one per CPU core, so the search runs in parallel without freezing the tab.
  3. Each worker hashes the challenge string plus a counter, the nonce, until a SHA-256 result starts with the required number of zeros.
  4. Then the browser sends the nonce back. The server checks it with one hash, marks the challenge as spent so it cannot be reused, and issues the cookie.
  5. The browser is redirected to the page it asked for.

What difficulty means

Difficulty counts leading zeros in the hexadecimal hash, and each hex digit has 16 possible values. Difficulty 2 needs about 256 attempts on average, difficulty 4 about 65,536, and difficulty 6 about 16.7 million. Each step of two multiplies the client’s work by 256, while the server still checks a single hash.

The v1.28.0 pre-releases add WebAssembly checks based on argon2id, hashx and SHA-256, counted in bits instead of hex digits. Argon2id is memory-hard, so the work leans on RAM as well as CPU. For browsers with JavaScript off there is a meta refresh challenge that only asks the client to wait a set number of seconds and reload.

Passing earns a cookie (named techaro.lol-anubis-auth plus a suffix since v1.27.0) that carries a signed JSON Web Token. The token holds the challenge, the nonce, the passing hash, the time it was issued and an expiry one week later. Anubis signs it with an ed25519 key, or with a shared HS512 secret when several instances must accept each other’s tokens.

Two bindings decide when the challenge comes back.

The IP binding. The installation reference sets JWT_RESTRICTION_HEADER to X-Real-IP by default. The token stores a hash of the client address at issue time, and every later request is checked against the current one. A different address means the cookie is cleared and the challenge starts over.

The rule binding. The token also carries a hash of the policy rule that issued it. If a later request is weighed into a different threshold, the old pass does not count and a new challenge is served.

Who gets challenged, and how hard

Anubis does not challenge everything. Its policy file sorts each request by path, User-Agent, headers, IP range and, from 1.28.0 (in pre-release as of October 2026), GeoIP country and ASN. Rules can ALLOW, DENY, CHALLENGE or WEIGH. Weighing adds points, and thresholds turn the total into an action.

The shipped default policy (read October 3, 2026) adds 10 points to anything whose User-Agent contains “Mozilla” or “Opera”, which covers every browser and every scraper pretending to be one. It adds 10 more for requests from Brazil or China and 10 for three cloud networks (Cloudflare, Huawei Cloud and Alibaba Cloud), once the site owner loads the GeoIP databases.

WeightDefault actionWhat it means for a browser
0 or lessAllowClients a rule vouched for
1 to 9Meta refresh, 1 secondWait and reload, no JavaScript
10 to 19Proof of work, difficulty 2An ordinary browser on an unweighted network
20 to 29Proof of work, difficulty 4Browser plus one weighted country or ASN
30 or moreProof of work, difficulty 6Browser plus several weights

Some traffic never meets the puzzle. Paths such as /robots.txt, /.well-known/, the favicon and /sitemap.xml stay open. Git clients that send the standard headers pass, so git clone keeps working on a forge behind Anubis. Search crawlers from Google, Bing, Apple, DuckDuckGo and others are allowed when their User-Agent and their published IP ranges both match. AI crawlers that announce themselves land on a deny list in the default “aggressive” preset.

Anything no rule matches is allowed through. Both challenge and deny pages return HTTP 200, because, in the policy file’s words, the most aggressive scraper bots “really, really, want an HTTP 200” and stop once they get one. A crawler that logs only status codes will think it fetched the page.

Why sites put Anubis in front

Load was the trigger. In March 2025, Libre News reported figures from GNOME’s sysadmin: GitLab saw about 81,000 requests in around two and a half hours, and only about 3% of them passed the proof of work. Forges are expensive to crawl: every commit, blame view and diff is a fresh page rendered from the repository.

The known instances list now includes Codeberg, Gitea, the Arch Linux wiki, FFmpeg’s trac and git web, FreeBSD’s svnweb, OpenWrt and several university library catalogues. The common thread is a small operator, dynamic pages and no budget for a commercial bot manager.

Deploying it in front of a site

Anubis sits between the web server that terminates TLS and the application. The installation reference lists the settings most sites touch:

BIND=:8923                    # where Anubis listens
TARGET=http://localhost:3000  # the app it protects
POLICY_FNAME=/etc/anubis/botPolicies.yaml
COOKIE_EXPIRATION_TIME=168h   # one week, the default

The setting that breaks most installs is the client IP. Anubis reads X-Real-IP, or flattens X-Forwarded-For to the first public address from the right, and it always strips CGNAT ranges and, by default, private ones. Behind a CDN that means every visitor can appear as the CDN’s address. The client IP caveats page warns that this shows up as an infinite challenge loop, and the fix is to pass the CDN’s real-client header through.

Where Anubis proof of work falls short

The sharpest critique came from security researcher Tavis Ormandy in 2025. His analysis argued that the cost is trivial for a crawler with cloud compute and high for people on limited devices. He wrote a short native solver that cleared a challenge in milliseconds and estimated the compute bill would not reach a cent a month until several million sites ran Anubis.

In August 2025, The Register reported that Codeberg said AI crawlers had learned to solve the Anubis challenges, and that some of the bots appeared to run on networks controlled by Huawei. Codeberg staff said Anubis had saved them, over the past months, from maintaining blocklists by hand.

Anubis’s answer has been to stack more checks on the puzzle. Weights by ASN and country, memory-hard WebAssembly puzzles, a honeypot of hidden links that only a careless HTML parser follows, and a headless browser detector in the commercial edition all aim at identity rather than cost. In March 2026, GNOME moved GitLab’s bot management to Fastly’s edge and switched Anubis off there.

Anubis vs other proof-of-work checks

Proof of work shows up in several products, and they differ in where they run and what else they check.

Cloudflare’s Turnstile documentation (updated August 2026) lists proof of work as one of several signals, next to proof of space, web API probing and behaviour checks. Anubis leads with the puzzle and adds signals around it. The self-hosted widgets guard one form, which suits a comment box or sign-up page more than a whole forge.

Seeing the page as a visitor

Anubis proof of work runs in the browser without asking for anything, and the site owner chose to put it there. The Anubis FAQ says plainly that it does not mine Bitcoin or any other currency; the hashes it computes are thrown away once one passes.

When the page hangs or loops, the cause is usually on the client side. JavaScript or the JIT compiler is off, so the hashing crawls. A privacy extension such as JShelter blocks the Web Workers. Cookies are blocked, so the pass never sticks. Or the IP keeps changing, through a VPN that rotates exits or a phone hopping between networks, and the IP binding resets the pass. The FAQ lists Chrome 75, Firefox 120, Safari 10 and Pale Moon 33 or newer as supported.

What a proxy changes with Anubis

A proxy changes the network origin of a request. With Anubis that matters in three places, and in none of them does it skip the puzzle or override the site’s decision.

The pass resets on a new address. Because the token is bound to X-Real-IP by default, a rotating residential proxy set to a new IP on every request meets a fresh challenge on every request. The same binding is why a person on a stable home or office address meets the page about once a week, while a phone user whose carrier keeps reassigning the address meets it far more often.

The exit decides the weight. A request from a weighted country or a weighted cloud ASN can land one threshold higher, which means a harder puzzle and, through the rule binding, a pass that does not carry over. Datacenter proxies sit on hosting networks, which makes them the exit to use when checking how a policy treats cloud traffic.

A deny is final. If the policy denies an AI user agent, a different network does not change the answer. If it denies an address range, the operator’s decision stands, and routing around it is exactly the traffic the tool was installed to stop. The routes that work are the ones the site offers: git clone over the forge’s own protocol, the forge’s API, published dumps and feeds, or a request to the operator. The policy file can allow a named crawler from a fixed address range, which is how search engines get through. A fixed address the operator can add, such as a static ISP proxy, fits that request.

Testing your own deployment

Here the legitimate proxy job belongs to the site operator. Before turning on GeoIP weights, it pays to see the site the way real visitors in Brazil, on a carrier network or on a cloud desktop will see it. Mobile proxies put the browser behind a carrier address that can change mid-session, which shows how often phone users get re-challenged under the IP binding. Residential exits by country show whether a country weight turns a difficulty 2 page into a difficulty 4 page for ordinary home users. Count challenges per ten page loads and the time each one takes, per exit type, before and after a policy change.

Which route fits your job

If you are a visitor, let the check run once with JavaScript on and cookies allowed, and expect it again after a week or after your IP changes.

If you run a site, start from the default policy, load the GeoIP databases only if you mean to weigh countries or networks, and test from carrier and residential networks before you ship a weight. Keep JWT_RESTRICTION_HEADER on unless your users’ IPs churn so often that the re-challenges cost more than the abuse.

If you run a crawler or an agent, check 200 responses for the challenge page markup, identify your bot honestly, and use the API, git clone or a dump where the site offers one. Where Anubis proof of work stands between your job and the data, ask the operator for an allow rule; a fixed address makes that request easy to grant.

Frequently asked questions

Anubis proof of work is a challenge the open-source Anubis reverse proxy shows before a protected site loads. The browser searches for a nonce whose SHA-256 hash with a random server string starts with a set number of zeros, then receives a signed cookie. The cost is small for one visitor and adds up for a crawler fetching many pages.

The site's operator put Anubis in front of the site to cut load from automated crawlers, and your browser matched a rule that asks for a challenge. Browsers are challenged because scrapers use the same User-Agent. The page clears by itself in a moment when JavaScript and cookies are allowed.

The default pass lasts seven days. It is also bound to your IP address and to the policy rule that issued it, so it ends early if your address changes or if a later request is weighed into a different rule. Clearing cookies resets it too.

It stops the bulk of low-effort crawlers that do not run JavaScript, and its default policy denies AI crawlers that name themselves. Crawlers that run the puzzle can pass it: Codeberg reported in August 2025 that AI crawlers had learned to solve its Anubis challenges. That is why newer versions add network weights, honeypot links and headless browser checks.

No. The Anubis FAQ states that it does not mine Bitcoin or any other currency. The hashes are a throwaway puzzle, and the work stops as soon as one result meets the difficulty.

Not with the default policy. It allows crawlers from Google, Bing, Apple, DuckDuckGo and others when both their User-Agent and their published IP ranges match, and it leaves robots.txt and sitemap.xml open. A custom policy that removes those rules can block search engines.

A proxy changes only the network the request comes from; the browser still has to solve the puzzle, and a deny rule still denies. Because the pass is bound to the IP, rotating exits brings the challenge back more often. The working routes are the site's API, git clone, published dumps or an allow rule from the operator.

Researched and drafted with AI tools, then checked against our publishing rules before it went live: 17 outside links, 5 links to other proxymint pages, no prices and a fact-check pass against our product records. How we write.