Skip to content

Bind SIWX session tokens to origin/offer (audience claim) #828

Description

@aly-obol

Context

Filed for internal follow-up from an external security researcher report. Tracked here rather than via the bug bounty program, since obol-stack is out of the program's scope.

The SIWX one-shot EIP-4361 verification correctly binds the signed message to the request host (Authenticate / expectedDomain in internal/x402/siwx.go). However, the reusable session token minted afterwards does not carry that binding:

  • MintSession (internal/x402/siwx.go) signs siwxSessionClaims{ Wallet, Exp } with the per-process HMAC secret. There is no host, origin, or offer claim.
  • VerifySession checks only the HMAC signature and expiry, then returns the wallet.

Because a single verifier instance serves multiple routes/offers and can front multiple origins (see the shared-origin vs dedicated-hostname handling in internal/x402/authgate.go), a session token minted after signing in to one offer is accepted on another offer served by the same verifier, after which X-Verified-Wallet is injected for that wallet on the second offer. In a deployment where offers have differing trust levels, this permits cross-offer reuse of a session token (an audience-confusion weakness).

Scope note on blast radius: the session secret is generated per verifier process (NewSIWXAuthenticator -> crypto/rand), so a token never crosses separate verifier instances. The concern is confined to a single verifier instance that fronts more than one offer/origin.

Changes

  • Add an origin/offer (audience) claim to siwxSessionClaims in internal/x402/siwx.go.
  • Populate it at MintSession time from the verified request host/offer.
  • Enforce it in VerifySession, rejecting a token presented on an origin/offer other than the one it was minted for.
  • Add a regression test: a token minted for offer A is rejected when presented on offer B.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions