Body
Hi team,
POST /api/contracts/escrow/refund takes a client-supplied circleContractId, checks that the caller is authenticated, and then calls Circle's refundByRecipient against the matching escrow agreement. The route doesn't check that the caller is actually a party to that agreement — there's no comparison between the caller's wallet and the agreement's depositor_wallet_id / beneficiary_wallet_id before the refund goes through.
In a deployed setting with real users, that means any authenticated user could trigger a refund on an escrow agreement between two other parties, without either party's involvement. That undermines the two-party guarantee escrow is supposed to provide, and it would also attribute the resulting transaction record to the wrong profile.
Flagging this as a hardening suggestion rather than a vulnerability report — no exploit steps here, just pointing at the missing check in the route logic.
Ask
Add an ownership check in the refund route that compares the caller's wallet against depositor_wallet_id and beneficiary_wallet_id on the target agreement, and reject with a 403 if neither matches, before calling refundByRecipient.
Happy to open a PR if useful.
Context: noticed this while evaluating Arc reference implementations for a project I'm building (circlefin/arc-node#268).
Body
Hi team,
POST /api/contracts/escrow/refundtakes a client-suppliedcircleContractId, checks that the caller is authenticated, and then calls Circle'srefundByRecipientagainst the matching escrow agreement. The route doesn't check that the caller is actually a party to that agreement — there's no comparison between the caller's wallet and the agreement'sdepositor_wallet_id/beneficiary_wallet_idbefore the refund goes through.In a deployed setting with real users, that means any authenticated user could trigger a refund on an escrow agreement between two other parties, without either party's involvement. That undermines the two-party guarantee escrow is supposed to provide, and it would also attribute the resulting transaction record to the wrong profile.
Flagging this as a hardening suggestion rather than a vulnerability report — no exploit steps here, just pointing at the missing check in the route logic.
Ask
Add an ownership check in the refund route that compares the caller's wallet against
depositor_wallet_idandbeneficiary_wallet_idon the target agreement, and reject with a 403 if neither matches, before callingrefundByRecipient.Happy to open a PR if useful.
Context: noticed this while evaluating Arc reference implementations for a project I'm building (circlefin/arc-node#268).