Skip to content

/verify endpoint has no nonce protection — bundles can be replayed indefinitely #20

@OkeyAmy

Description

@OkeyAmy

The Problem

Nonce replay protection was added to the MCP and A2A middleware (commit 4f7c307). The `POST /verify` endpoint at `cmd/server/main.go:95` calls `verify.Chain` directly and has no nonce check. Bundles can be replayed through `/verify` indefinitely.

This matters because `/verify` is not an internal endpoint. It is the primary integration point for the SDK and for any caller that does not go through the middleware. If a client captures a valid signed bundle, they can submit it to `/verify` as many times as they want, getting a valid `VerificationResult` back each time. Any downstream system that gates on a `{"valid":true}` response is bypassed.

Where It Breaks

```go
// cmd/server/main.go:119
result := verify.Chain(req.ChainBundle, reqDeps)
```

No nonce check before this line.

What Must Change

Wire the same `nonceStore` into the `/verify` handler. The check is already extracted into `checkNonceReplay()` in `pkg/middleware/decode.go` — one call, one return-if-true.

```go
if checkNonceReplay(w, req.Invocation, nonceStore) {
return
}
result := verify.Chain(req.ChainBundle, reqDeps)
```

The nonce store is already constructed in `main()` and available in scope.

Severity

HIGH. The nonce protection is inconsistent. The whole point of replay protection is that it applies everywhere. A middleware that rejects replays but a direct endpoint that accepts them is a bypass, not a defense.

Metadata

Metadata

Assignees

No one assigned

    Labels

    highHigh severitysecuritySecurity vulnerability or hardening

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions