# Final x402 / Bazaar Release Audit

- **Audited worktree:** `/home/user/workspace/vaultfire-audit-final-x402-bazaar-20260822`
- **Starting revision:** `42b45865473d4692c8f9221335d94060a4d08948`
- **Audit branch:** `audit/final-x402-bazaar-20260822`
- **Scope:** retained V2 source/registry, prepared V3 SDK/test surface, Coinbase Bazaar metadata artifacts, public discovery, persistence/webhook/cron guards, and Base/Solana rail claims.
- **Safety boundary honoured:** no wallet, signature, payment, chain write, deployment, listing publication, route change, or live POST was performed. Test receipts and hashes are deterministic in-process fixtures only, not settlement evidence.

## Release disposition

**DO NOT enable V3 payments or publish/represent Bazaar candidates as live.** The exact checked-in application source is fail-closed for every `/api/x402/*` request and its public `.well-known/x402.json` is non-payable. The prepared V3 SDK has no checked-in `app/api/v3` runtime route and the PR9 money-movement flags are default-off. This preserves the source-level V2/V3 safety posture.

The checked-in registry is an inventory, not deployment or settlement evidence: 147 entries (143 V2, 4 V3); 77 have prices and are labelled Bazaar **candidates**. Of the 77 candidates, 29 only have `metadata-configured-unverified` Solana options; 48 explicitly say `read-only-api-no-solana-settlement`. The registry readiness command correctly refuses readiness without owner evidence. No candidate was queried as a public Bazaar listing and no Solana route was described as settled.

## Material fixes made

### F-01 — prepared V3 payment identity / receipt substitution (fixed)

**Pre-fix impact:** the deterministic prepared facilitator stored receipts only by `paymentId` and returned an existing receipt even where a newly signed request used the same `paymentId` with a different `requestId`. A caller could therefore receive fulfillment for a second request from a receipt that belonged to the first. The V3 SDK also treated a successful receipt as structurally opaque, so a receipt for a different payment/request/resource could be accepted by the client.

**Fix:**

1. Receipt schema now carries `paymentId`, `requestId`, HTTP `method`, `path`, `network`, and validates all original challenge/payment bindings in the client, including configured `chainId`, asset, atomic amount, payer, payee, protocol version, and finality.
2. The prepared facilitator rejects a reused settled `paymentId` for a different request with `409 payment_id_reused`, while retaining same-request delivery retry semantics.
3. Client rejects an unbound initial success, malformed receipts, receipt substitution, wrong-chain receipts, an expired challenge, and a 402 challenge whose method/resource does not match the request before it signs or retries.
4. Regression coverage now includes underpayment and overpayment, duplicate identity, cross-request replay, substituted receipt, wrong receipt chain, malformed header/signature, bad asset/network/payee/version, stale expiry, finality-not-reached, delivery retry, and idempotency.

**Limit:** this is prepared/in-process V3 code only; it is not evidence of a deployed facilitator or a real settlement.

## Binding and adversarial-flow assessment

| Binding / attack | Checked result | Boundary |
|---|---|---|
| Resource + HTTP method | Challenge and signed payment contain both; sandbox checks request and challenge values; client now rejects a mismatched challenge before signing. | Prepared V3 regression only; V2 runtime is globally gated. |
| Chain + token/mint + atomic amount + payee | V3 challenge/payment signs `network`, `asset`, `amount`, `payee`; sandbox requires exact equality; client binds receipt network, asset, amount, payee and configured chain ID. | Base/EVM config is modeled. No real Base transaction/RPC proof. Solana is not asserted settled. |
| Payer + signature | Canonical length-delimited payload is Ed25519-signed in the deterministic model; wrong payer/signature reject before settlement. | Fixture signer only; no wallet used. |
| Expiry / early settlement | Sandbox rejects expiry and requires finality rank. Client rejects expired challenge before signing. | V3 type has no `validAfter` claim; see blockers. |
| Replay / duplicate / concurrent retry | Request binding rejects cross-route replay; new payment-ID conflict rejects second signed request; same request returns stored result; idempotency key returns cached result. | In-process map only; distributed store concurrency is unproven. |
| Facilitator failure + delivery retry | Timeout gets retry with the same payment; post-settlement delivery loss returns stored receipt without another settlement. | Deterministic facilitator only; no external facilitator proof. |
| Receipt substitution | Receipt is now typed and bound to payment, request, method, path, network, chain, token, amount, payer, payee, version, and finality. | Receipt is not cryptographically verified against a facilitator/chain; no live rail was contacted. |
| Reorg / finality | Test gates `soft` below required `safe` and blocks fulfillment. | No Base/Solana RPC finality/reorg observation; remains a release blocker. |
| OPTIONS/preflight + discovery separation | Checked-in global x402 middleware blocks every method for `/api/x402/:path*`; disabled discovery has no endpoints, networks, assets or payee. Read-only public OPTIONS responses were captured separately and do not match the HEAD gate, showing deployment drift. | OPTIONS did not send a payment header or POST body. |
| Webhook / cron persistence | Static release suite verifies explicit `WEBHOOK_ADMIN_TOKEN` write auth and heartbeat failure without auth/persistence. | No live webhook nor persistence write attempted. |

## Endpoint / flow matrix

`endpoint-flow-matrix.csv` is exhaustive for all 147 generated registry entries. It preserves each route's method, path, V2/V3 version, price, asset, network, payee, finality, idempotency rule, Bazaar state, and Solana status. `endpoint-flow-matrix-summary.json` gives the aggregate counts and alignment metadata.

Runtime labels in the matrix are intentionally conservative:

- **V2 `/api/x402/*`:** retained source/registry only; the HEAD middleware returns a fail-closed gate before route processing.
- **V3:** prepared only, default-off; no `app/api/v3` route implementation exists in the checked-in application.
- **Bazaar candidate:** metadata status only; not a listing or publication claim.
- **Solana `metadata-configured-unverified`:** not a settlement claim.

## Read-only public check and live limitation

Only `OPTIONS` requests were sent publicly, without `X-Payment`, body, wallet, or payment. On 2026-08-22, the public URLs returned 204 preflight responses instead of the expected HEAD source gate. The response log is `logs/live-readonly-options.log`. This is evidence of **deployment/source drift**, not a payment result, receipt, route approval, Bazaar listing, or settlement. The deployed public behavior cannot be accepted as validating this exact revision until the owner resolves the mismatch and supplies an immutable deployment identity.

## Residual release blockers

1. **Deployment identity mismatch (blocking):** public preflight behavior did not match the exact HEAD middleware. Require immutable deployment SHA, build artifact checksum, and re-run read-only checks against the deployed revision.
2. **No owner readiness evidence (blocking):** `check:bazaar-readiness` intentionally fails because `pr7/evidence/bazaar-live-evidence.json` is absent. Do not create synthetic evidence.
3. **No Base settlement proof (blocking):** no owner-authorized wallet/budget, facilitator attestation, transaction, receipt verification, confirmation policy observation, or reorg drill was available.
4. **No Solana settlement proof (blocking):** 29 option records are metadata-only and 48 say no Solana settlement; no mint/payee/finality route may be called settled.
5. **V3 valid-after policy incomplete (blocking for V3 enablement):** prepared V3 challenge/payment types bind expiry but do not carry a `validAfter` field. The product must specify and test a signed not-before policy before a V3 payment enablement.
6. **Distributed concurrency/persistence unproven (blocking for writes):** in-process idempotency/receipt maps pass tests, but no production transactional uniqueness constraint, outage recovery evidence, or webhook/persistence authenticated delivery proof was supplied.
7. **Vendored Node dependency install incomplete (non-code verification blocker):** the lockfile install exceeded the environment's 630-second command limit twice and left partial modules. The dependency-free release safety suite and secret scan passed, but vendored Jest/TypeScript/lint commands requiring the incomplete installation could not run; exact errors are retained in logs.

## Canary plan (owner-controlled only)

1. **Keep current global x402 gate enabled** until every blocker has owner evidence. Confirm deployed commit/build identity first; do not infer from domain behavior.
2. In an isolated non-production environment, provide a dedicated test facilitator, Base RPC, Solana RPC, test payers/payees, exact mint/token metadata, an explicit wallet authorization, and a hard maximum spend budget. No authorization means no payment test.
3. Start with **one Base read-only priced route**, a unique payee, exact atomic amount, a single payer, strict `safe` finality, short expiry and explicit future `validAfter` once implemented. Assert challenge/payment/receipt fields byte-for-byte and persist an immutable evidence bundle.
4. Exercise the negative matrix: malformed/under/over payment; wrong resource/method/network/token/payee; stale/early; wrong payer; failed/self settlement; receipt substitution; concurrent retry and duplicate payment ID; persistence unavailable; spoofed webhook; finality regression/reorg simulation. Confirm no fulfillment or write on every negative case.
5. Prove idempotency in the actual durable store and prove facilitator receipt/transaction correspondence with read-only chain lookups. Test a controlled reorg/finality downgrade policy before any write route.
6. Add Solana only after owner-provided canonical mint, payee, token-program, verifier/facilitator, commitment/finality, and transaction evidence. Mark all other Solana options unavailable.
7. Publish a Bazaar record only after owner evidence validates a deployed route. Treat metadata candidate files as inputs, not a live announcement. Roll back by restoring the global gate and disabled discovery on any mismatch.

## Evidence files

- `endpoint-flow-matrix.csv` — exhaustive 147-row registry/flow matrix.
- `endpoint-flow-matrix-summary.json` — inventory totals and explicit non-live methodology.
- `build_endpoint_flow_matrix.py` — reproducible matrix generator.
- `COMMANDS_AND_RESULTS.md` — exact commands, child exit codes, and log locations.
- `logs/` — captured command output, including expected readiness denial and dependency limitations.
