# Liquidator can set up referrals for other users

Liquidator can set a referrer on a liquidated user's order, locking that referrer permanently and blocking the user from choosing their own.

- Payout: Contest reward
- Severity: medium
- Program: Perennial V2 3
- Credited: bin2chen
- Disclosed: 2024-02-28
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-02-perennial-v2-3-judging/issues/22
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-perennial-v2-3%3AM-7
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Market.sol referral processing in liquidation orders
**Root cause:** _processReferrer only skips when both maker/taker referral are zero; liquidation orders can carry a referrer, and _storeUpdateContext persists it under the new currentId, carrying it forward permanently.
**Steps:**
1. User has no referrer and meets liquidation criteria.
2. Liquidator submits a liquidation order with a non-zero makerReferral/takerReferral set to attacker-chosen address.
3. `_processReferrer` sees updateContext.referrer == 0 and sets it to the liquidator's referrer.
4. `_storeUpdateContext` writes referrers[account][currentId] = attacker referrer.
5. On subsequent currentIds the referrer is loaded and re-stored, so user can never set their own referrer; any attempt reverts with MarketInvalidReferrerError.
**How found:** Code reading of _processReferrer/_storeUpdateContext: noticed the only guard is non-zero referral fields, which liquidation orders satisfy, and that referrer is carried across currentIds rather than reset.
**Exploitation:** Liquidator front-runs/executes liquidation with a chosen referral address, permanently binding the victim's account to that referrer so referral fees accrue to the attacker and the user cannot change it.
**Insight:** When auditing state that is 'set once', check whether privileged/forced flows (liquidations, keeper actions) can write it before the user does, and whether the value is carried across version/id increments instead of reset.
