Description
release_milestone() checks for insufficient escrow balance defensively, but there's no mechanism preventing two release calls for different milestones on the same escrow from being processed in a way that double-counts available balance. In a single-threaded Soroban execution model this may not be exploitable today, but the lack of an explicit invariant check (e.g. re-deriving available balance from storage right before transfer) makes this fragile under future contract changes (e.g. batched or cross-contract calls).
Where
contracts/milestone_escrow/src/lib.rs (~line 381-385)
Acceptance Criteria
Description
release_milestone()checks for insufficient escrow balance defensively, but there's no mechanism preventing two release calls for different milestones on the same escrow from being processed in a way that double-counts available balance. In a single-threaded Soroban execution model this may not be exploitable today, but the lack of an explicit invariant check (e.g. re-deriving available balance from storage right before transfer) makes this fragile under future contract changes (e.g. batched or cross-contract calls).Where
contracts/milestone_escrow/src/lib.rs(~line 381-385)Acceptance Criteria