Anubis ships WebAssembly proof-of-work after a year-long build
Xe Iaso, CEO of Techaro, published a blog post on September 6, 2026 describing a roughly year-long project to add WebAssembly-based proof-of-work checks to Anubis, the challenge system site owners run to slow down aggressive AI scrapers. The work spanned hundreds of commits, five generations of pull requests, dozens of tests, a partial rewrite in Rust, and at least three occasions when the author's own workstation ran out of RAM.
The new checks let administrators switch a challenge's algorithm to argon2id, a memory-hard proof-of-work function, instead of the existing CPU-only 'fast' challenge. Iaso frames this as closing off GPU-based solvers built for the old challenge, joking that the 'hey Claude vibeslop me a CUDA Anubis solver' route is effectively dead. A second, unrelated fix rides along: the old 'fast' challenge counted leading zero hex nibbles in a hash rather than leading zero bits, which meant each single-point increase in difficulty made a challenge 16 times harder to solve in the worst case, a scaling bug now corrected.
The core design idea is that the same compiled WebAssembly binary, written in Rust and compiled with no-std for wasm32-unknown-unknown, runs on both the browser client solving a challenge and the Go-based server validating it, so the two sides stay in lockstep the way a game console and its authentication chip do. Because some browsers and privacy modes (iOS Lockdown Mode, GrapheneOS Vanadium's default setup) disable WebAssembly outright, Iaso also built a JavaScript fallback by running the WebAssembly through Binaryen's wasm2js tool rather than writing and maintaining a second implementation by hand.
That fallback build is where the project stalled for months. Iaso hit what turned out to be a genuine LLVM compiler bug: an LLVM pass iterated over exception-handling blocks in machine pointer order, so each build of the compiled output drifted by about 29 bytes from the last, breaking attempts at a reproducible, committed build artifact. Disabling ASLR made results consistent within a single boot, which pointed the investigation at the compiler rather than the input code. Iaso bisected Binaryen versions by building each from source and settled on version 128, the newest available at the time, and waited for a fixed wasi-sdk release before finishing the pipeline. Separately, browser testing turned up a Chrome compile error on versions as old as 75 up through Chrome 100, traced to a Rust standard-library function compiled with WebAssembly reference types that Chrome's strict-MVP parser could not read; Iaso used a Claude Opus and GLM 5.2 loop to fuzz wasm-opt flags until the output parsed cleanly on Chrome 75, while still targeting the JavaScript fallback build to the older Chrome 66 as extra margin.
Browser coverage was tested with a homemade harness called 'chromesweep' that spins up many isolated Chrome instances, each sandboxed inside a Kata containers microVM behind a strict network policy, to hit a test Anubis instance; the browser library behind it is published as TecharoHQ/gubal. The WebAssembly checks ship off by default in Anubis v1.28.0 ('Wuk Lamat'); Iaso plans to turn them on by default in v1.29.0, timing dependent on feedback from administrators and users, with no calendar date given. The post states plainly that AI was not used to write its prose, only to help generate a diagram, and that the wasm2js JavaScript fallback still lacks a working progress-bar update as one of several known rough edges left to fix.
Key facts
- Anubis will ship WebAssembly-based proof-of-work checks, off by default in v1.28.0, with a plan to make them the default in v1.29.0 depending on feedback.
- The new argon2id memory-hard challenge is meant to kill GPU-accelerated solvers built for the old CPU-only 'fast' challenge.
- A separate bug fix corrects the old difficulty scaling: counting hex nibbles instead of bits made each +1 difficulty step 16 times harder in the worst case.
- The client and server run the identical compiled WebAssembly binary; browsers without WebAssembly fall back to JavaScript generated from it via Binaryen's wasm2js.
- The build pipeline was blocked for a stretch by a genuine LLVM compiler bug causing 29-byte build-to-build drift, fixed upstream in wasi-sdk; Binaryen version 128 was chosen by bisection.
Why it matters
Anubis exists to make mass scraping by AI companies more expensive without blocking ordinary visitors, and this release changes the shape of that trade-off twice over. Switching the proof-of-work algorithm to argon2id makes the challenge memory-hard rather than just CPU-hard, which specifically targets GPU-based solvers built to brute-force the old check cheaply. Separately, the release quietly fixes a scaling bug that had been in Anubis since the 'fast' challenge shipped: because it counted leading zero hex nibbles instead of bits, raising difficulty by a single point made a challenge 16 times harder in the worst case rather than scaling smoothly, an error the author says was a mistake in retrospect and is folded into this same release since challenge internals were already being touched.
Who it affects
Directly, this affects administrators who run Anubis in front of their sites and can now opt into the WebAssembly-based argon2id challenge in their threshold or bot-rule configuration. Indirectly, it affects the operators of scraping and solving tools built against the old CPU-only challenge, since the memory-hard function is designed to make GPU-based solving markedly less viable. It also affects visitors on older or restricted browsers, since Anubis still supports Chrome versions back to 75 and ships a JavaScript fallback aimed at Chrome 66 for users on iOS Lockdown Mode, GrapheneOS Vanadium, or other setups where WebAssembly is disabled by policy.
How to use it
Administrators enable the new checks by setting a challenge's algorithm to argon2id (with a chosen difficulty value) inside an Anubis threshold or bot-rule configuration; the feature ships off by default starting in Anubis v1.28.0, codenamed 'Wuk Lamat'. Xe Iaso says the plan is to turn it on by default in v1.29.0, but that timing is explicitly contingent on feedback from administrators and users rather than fixed to a date. No pricing or licensing terms are mentioned; Anubis is described only in terms of its configuration, not commercial terms.
How solid is it
The account comes directly from Xe Iaso, Techaro's CEO and the engineer who did the work, published on the company's own blog with extensive supporting detail: code and configuration snippets, an interactive difficulty-scaling diagram, exact version numbers (Binaryen 128, target Chrome 75 and 66, the Chrome 74/85/91 feature-shipping dates baked into the build script's own comments), and a specific description of the LLVM exception-handling-block bug that caused build drift, traced by disabling ASLR to get consistent results within a boot. The post states outright that its prose was written without AI assistance, with the sole AI use being Claude Opus helping produce a visual diagram, and that a Claude Opus and GLM 5.2 loop was used only to fuzz compiler flags, not to write the writeup. No independent source corroborates the account beyond the post itself; it should be read as a first-person engineering narrative rather than a third-party audit.
Risks and caveats
The author flags several known gaps rather than presenting the work as finished: the JavaScript fallback generated via wasm2js has no way yet to update the in-progress solving indicator, since its update-nonce callback is currently stubbed out; the new WebAssembly build is described as 'ridiculously performant', which the author warns may itself force administrators to raise difficulty values to compensate; and a planned mobile-request classifier meant to give phones appropriate leniency is still an early prototype. Because a single compiled binary is shared between client and server, the author notes a bug in that shared code could in principle let a client send a value the server wrongly accepts as valid, though this is described as a theoretical rather than observed concern. Exact performance gains over the old JavaScript and Go implementations are not quantified in the source beyond that qualitative 'ridiculously performant' claim, and no fixed date is given for when the WebAssembly checks will become the default.
“I have no intention to rewrite Anubis in Rust or anything as drastic as that.”
— Xe Iaso, CEO of Techaro