Skip to main content
Ward
x402 on Algorand

Prove your facilitator can’t be cheated

Ward is an adversarial test framework that runs real, tampered payments against a real x402 facilitator and reports exactly which correctness guarantees hold — with reproducible, on-chain evidence for every result.

What Ward does

Every x402 facilitator promises the same thing: verify a payment correctly, then settle exactly what was verified. Nothing more, nothing less, exactly once. Ward checks whether a given facilitator actually keeps that promise. It plays the adversary itself — building real, correctly-signed payments, then deliberately tampering with them:
  • A mutated amount
  • A redirected receiver
  • An unsigned fee-payer leg, rewritten after signing
  • A key that’s no longer the account’s spending authority
Then it asserts that the facilitator’s /verify and /settle endpoints reject exactly what they should. Nothing here is mocked. Ward drives a real, self-hosted facilitator process end to end and reports pass/fail with the full request and response trail behind every result.

Quickstart

Fund accounts, boot a facilitator, and run the full guarantee suite in a few commands.

Correctness Guarantees

The eight properties Ward checks, and exactly what each one proves.

Command Line

ward init, ward test, ward fuzz, and ward report in detail.

Hosted Verification API

A paid, x402-gated HTTP endpoint that runs Ward against any facilitator URL you submit.

Why it exists

A USENIX Security ‘26 study tested 15 major x402 facilitators — collectively serving over 60,000 sellers and 360,000 buyers — and found authorization-correctness violations in every single one, spread across four classes:

Free Shopping

A client gets a resource without ever paying the amount the facilitator approved.

Asset Theft

Funds are moved to a receiver, amount, or asset the client never actually authorized.

Service Denial

Legitimate payments are rejected, or the facilitator can be knocked into a broken state.

Gas Abuse

A client forces the facilitator to spend unbounded, uncapped work rejecting doomed payments.
No facilitator in that study shipped with an automated way to verify it doesn’t have these problems. Ward is that missing test framework. It’s Algorand-first today, with a chain-agnostic core — so a second chain is a new adapter, not a rewrite. See Architecture for how that separation is enforced in code, not just claimed.

Two ways to use Ward

Clone the repository, self-host a facilitator with Docker Compose, and run ward test from the CLI against it. This is the right choice if you’re building or operating a facilitator and want the full evidence trail on your own machine. See the Quickstart.

What Ward tests against

Ward runs against GoPlausible’s x402-avm facilitator, self-hosted via Docker Compose. It uses the branch-v2-algorand-publish branch — since adopted into the official x402-foundation/x402 monorepo — and never the shared, public facilitator.goplausible.xyz instance. Every finding Ward produces is about a real, running facilitator process Ward controls end to end — never shared or production infrastructure.

How a check runs, end to end

Ward plays every role in this diagram except the facilitator, then tampers with the payload at the point a real attacker would — after the client signs, before the facilitator settles.

Ground truth, not guesses

Every wire shape and validation rule Ward relies on was read directly from the installed @x402/core / @x402/avm package source:
  • PaymentRequirements and PaymentPayload
  • The exact fee-abstraction group layout
  • The facilitator’s complete verify()/settle() algorithm, including its error codes
None of it was inferred from documentation — which turned out to diverge from the real implementation in several places. See the Decision Log for the full paper trail.