# Not verifying that transaction initiator is the actual participator allows malicious user to allocate full reward as Uniswap V2 pool

NudgeCampaign.handleReallocation trusts caller-supplied userAddress, letting an attacker flash-swap target tokens and register a Uniswap V2 pool as participator, capturing the full reward.

- Payout: Contest reward
- Severity: medium
- Program: Nudge.xyz
- Credited: Luc1jan
- Disclosed: 2025-04-29
- Write-up quality: 8/10
- Original: https://code4rena.com/reports/2025-03-nudgexyz#m-04
- Library page: https://bugbountylibrary.com/r/c4%3A2025-03-nudgexyz%3AM-04
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:chained vuln:access-control vuln:accounting-error vuln:business-logic vuln:flash-loan

**Target:** NudgeCampaign.handleReallocation via Li.Fi Executor.swapAndExecute
**Root cause:** handleReallocation accepts an arbitrary userAddress from calldata without checking it matches the swap initiator, so any address (e.g. a Uniswap V2 pair) can be registered as participator.
**Steps:**
1. Deploy attacker contract; ensure a Uniswap V2 pool exists for the target token.
2. Compute tokens needed: `unallocatedRewards * PPQ_DENOMINATOR / REWARD_PPQ`.
3. Call `pair.swap(toTokensRequired, 0, attacker, data)` to flash-borrow target tokens.
4. In `uniswapV2Call`, encode `handleReallocation(campaignId, address(pair), token, amount0, "")` as callData.
5. Build `LibSwap.SwapData` with callTo/approveTo = campaign, call `executor.swapAndExecute(txId, swaps, token, pair, amount0)`.
6. Campaign registers pair as PARTICIPATING with full reward; transfer borrowed tokens + 0.3% fee back to pair to settle flash swap.
**How found:** Code review of handleReallocation: noticed userAddress is caller-supplied and not bound to msg.sender/tx.origin, then reasoned that any address with sufficient target-token balance (a Uniswap V2 pool) could satisfy the backend balance check, enabling a flash-swap-funded fake participation.
**Exploitation:** Attacker flash-borrows target tokens from a Uniswap V2 pair, routes them through Li.Fi Executor into NudgeCampaign.handleReallocation with userAddress set to the pair itself, registering a valid participation backed by the pool's large balance. Tokens are returned to the pool in the same tx; only cost is the 0.3% swap fee. Full reward is allocated to the pool, draining unallocated rewards and DoSing the campaign.
**Escalation:** Repeated or scaled across campaigns; monitoring balance check passes because the pool holds ample tokens, so invalidation never triggers.
**Insight:** When a callback-style handler trusts a user-supplied 'beneficiary' address and a backend validates participation by token balance, look for any address that already holds a large balance of that token (DEX pools, vaults) and can be flash-funded within the same tx — the balance check becomes the bypass.
