AgentTrust
AgentTrust
verification

Adversarial harness

Fourteen hostile-scenario assertions that exercise the gate against malformed PDAs, replayed proofs, and corrupted state.

The adversarial harness sits alongside the Anchor end-to-end suite. While the e2e tests cover the happy + edge paths a normal integration would hit, the adversarial harness exercises the failure modes a hostile caller would try.

Source: tests/adversarial.spec.ts. Run via anchor test --skip-deploy --provider.cluster localnet.

The fourteen scenarios

Each scenario constructs a hostile input and asserts the program rejects it with a typed error rather than producing an Allow or silently mutating state.

#ScenarioExpected behaviour
1Forged AtomStats — wrong owner programDeny(AtomStatsWrongOwner) (code 9)
2Forged AtomStats — schema-version canary mismatchDeny(AtomStatsSchemaMismatch) (code 10)
3Forged AtomStats — tier byte > ATOM_TIER_MAX = 4Deny(AtomStatsSchemaMismatch) (code 10)
4Forged AtomStats — undersized bufferDeny(AtomStatsSchemaMismatch) (code 10)
5Replayed payment_id_hashaccount-already-in-use on FeedbackEmissionLog init; whole tx reverts
6Self-pay attempt — facilitator signing as both payer and payeeDeny from facilitator-signer-mismatch check
7Wrong attestor — attestation issued by a key not in accepted_attestors[]Deny(AttestationAttestorRejected) (code 14)
8Stale attestation — expires_at <= now_slot (and != 0)Deny(AttestationExpired) (code 12)
9Revoked attestation — revoked == trueDeny(AttestationRevoked) (code 13)
10Wrong subject — attestation's subject_asset doesn't match the payeeDeny(AttestationMissing) (code 11)
11Wrong capability — attestation's capability_hash doesn't match required_capability_hashDeny(AttestationMissing) (code 11)
12Multisig threshold bypass attempt — fewer distinct signers than thresholdThresholdNotMet (Anchor error)
13Multisig duplicate-signer attempt — same key signing twicecounted as one (pubkey-dedup); ThresholdNotMet if remaining distinct count is below threshold
14Velocity counter manipulation — now_slot < window_start_slot (clock-skew or replay)saturating_sub clamps elapsed to 0; window NOT expired; cumulative correctly preserved

What the harness covers that Kani doesn't

Kani's bounded model checker proves the pure-Rust composer's safety invariants over symbolic state. The adversarial harness covers the on-chain Anchor wrapper that Kani doesn't:

  • account-validation checks (owner mismatch, size mismatch, schema-version canary)
  • the init-only FeedbackEmissionLog + replay mechanism (Anchor's account-already-in-use semantics)
  • the Anchor-handler's signer constraints (facilitator self-pay, attestor key validation)
  • end-to-end on-chain tx behaviour the bounded composer can't see (idempotency, atomic revert)

The two together cover both the in-program decision logic (Kani) and the surrounding Anchor wrapper (adversarial harness). Either alone leaves gaps.

Why localnet, not devnet

Adversarial scenarios sometimes require constructing accounts the real Quantu programs would never produce (forged AtomStats with bad schema versions, forged ValidationAttestation PDAs with wrong owner). On localnet, the test fixture writes those raw bytes directly. On devnet, the only way to construct such an account is to compromise the real program — which we obviously can't do in CI.

Localnet also produces deterministic timing for slot-based assertions (clock-skew test #14). Devnet cluster-time variance would make that test flaky.

Reproduce

git clone https://github.com/agenttrust-labs/agenttrust && cd agenttrust
pnpm install
anchor build
anchor test --provider.cluster localnet --validator legacy --skip-build \
  --grep "adversarial"

Expected: 14 / 14 passing in ~30 s.

Where it complements other layers

  • PolicyVault unit tests (113 cases). Cover normal paths through every policy module.
  • Anchor TS e2e suite (50 cases). Cover the Anchor wrapper happy paths against real (or cloned) Quantu state.
  • Kani proofs (6 / 635 sub-checks). Cover the pure-Rust composer's safety invariants over symbolic state.
  • Adversarial harness (14 cases). Cover the failure modes a hostile caller would try.
  • MCP protocol conformance (21 cases). Cover the MCP wire protocol shape.
  • Adapter contract conformance (per-adapter test suites). Cover the FacilitatorAdapter contract.

The combination — 113 + 50 + 635 sub-checks + 14 + 21 + per-adapter — is what underwrites the v1 safety claim.

Source

On this page

⌘I