# Malicious registrant can front-run `RFPSimpleStrategy._allocate()` in order to change the `proposalBid` and get a bigger payout in the distribution

Registrant front-runs pool manager's _allocate() to raise proposalBid, then _distribute() pays out the inflated bid, draining pool funds.

- Payout: Contest reward
- Severity: high
- Program: Gitcoin
- Credited: 0xbepresent
- Disclosed: 2023-09-01
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-09-Gitcoin-judging/issues/497
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-09-Gitcoin%3AH-5
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:business-logic vuln:race-condition

**Target:** RFPSimpleStrategy.sol allocation/distribution logic
**Root cause:** _allocate() accepts the recipient without binding to the proposalBid the manager reviewed; the registrant can re-register with a higher bid before allocation lands. _distribute() then computes payout from the mutable recipient.proposalBid.
**Steps:**
1. Registrant calls `_registerRecipient()` with `proposalBid=10`.
2. Pool manager submits `_allocate(abi.encode(recipient))` to accept.
3. Registrant watches mempool and front-runs with a re-registration setting `proposalBid=50`.
4. Manager's `_allocate()` executes against the updated recipient, accepting bid=50.
5. Manager calls `_distribute()`; `amount = recipient.proposalBid * milestone.amountPercentage / 1e18` pays out the inflated bid.
**How found:** Code review of the register/allocate/distribute flow: noticed _allocate() decodes only the recipient address and never validates proposalBid against what the manager intended, while _distribute() trusts the stored bid.
**Exploitation:** Attacker registers with a low bid to be selected, then front-runs the manager's _allocate() transaction with a re-registration raising proposalBid. Since _allocate() only decodes the recipient address and checks status Pending, the inflated bid is accepted. On distribution, the payout formula uses the inflated proposalBid, letting the attacker drain pool funds via a single milestone.
**Escalation:** Single milestone with high amountPercentage can drain the entire pool balance.
**Insight:** When an accept/allocate function takes only an identifier, check whether any mutable field set by the counterparty (price, bid, amount) is later used for payout without being pinned in the accept call; mempool front-running of the accept tx lets the counterparty swap that field.
