Skip to content

Potential settlement gating issue: delegate agent runs before payment settlement #15

Description

@chenshj73

Hi, I noticed a possible payment-flow ordering issue while reviewing the current source.

In x402_a2a/executors/server.ts, _processPaidRequest verifies the submitted payment, records it as verified, then runs the delegate agent before attempting settlement:

const verifyResponse = await this.verifyPayment(paymentPayload, paymentRequirements);
...
this.utils.recordPaymentVerified(task);
await eventQueue.enqueueEvent(task);
...
await this._delegate.execute(context, eventQueue);
...
const settleResponse = await this.settlePayment(paymentPayload, paymentRequirements);

This means delegate logic can generate or enqueue business output after verification but before settlement succeeds. If settlement later fails, recordPaymentFailure() updates payment metadata/status, but it does not necessarily undo or suppress any delegate-generated events that may already have been enqueued or streamed.

Why this may matter:

  • Payment verification is not the same as completed settlement.
  • Settlement can still fail after verification.
  • A delegate agent may disclose paid content or perform a paid action before settlement success is known.
  • In event-streaming integrations, delegate output could already be visible to the client before settlement failure is recorded.

The included mock facilitator also supports the state where verification succeeds but settlement fails, which suggests this is a realistic flow to handle defensively.

A safer design would be to settle successfully before invoking the delegate agent for paid work, or to buffer delegate output and release it only after settlement success. If running delegate logic before settlement is intentional, it may be worth documenting that contract clearly and adding tests for the settlement-failure path to ensure paid output is not exposed unexpectedly.

I am reporting this as a potential issue rather than a confirmed exploit, since the final impact depends on the concrete event queue / streaming behavior used by an integration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions