# JokInTheBox staking: repeated unstake drains bonus rewards

JokInTheBox staking contract let an attacker repeatedly unstake index 0 to drain bonus rewards, netting ~9.2 ETH.

- Payout: Real-world hack
- Severity: high
- Program: JokInTheBox
- Credited: DeFiHackLabs
- Disclosed: 2024-06-11
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-06/JokInTheBox_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20240611-jokinthebox
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:reward-distribution

**Target:** ERC20 staking contract (stake/unstake with lock periods)
**Root cause:** The unstake function does not invalidate or advance the stake entry after withdrawal, so the same stake index can be unstaked repeatedly, each time paying out the lock-period bonus.
**Steps:**
1. Swap 0.2 ETH for JOK via Uniswap V2 router `swapExactETHForTokens`.
2. Call `jokStake_.stake(jok_.balanceOf(this), 1)` to stake with lockPeriod=1.
3. `vm.warp(block.timestamp + 3 days)` to pass the lock period.
4. Loop `try jokStake_.unstake(0) {} catch { break; }` to repeatedly unstake the same index.
5. Swap accumulated JOK back to WETH via `swapExactTokensForTokensSupportingFeeOnTransferTokens`.
6. Repay 0.2 ETH flash loan; keep ~9.2 ETH profit.
**Exploitation:** Attacker flash-funded 0.2 ETH, bought JOK, staked with a short lock period, waited 3 days, then looped unstake(0) to repeatedly collect the bonus payout on the same stake entry, swapped proceeds to WETH and repaid the loan.
**Insight:** When a staking contract keys withdrawals by index, check whether the entry is marked consumed or the index advanced after unstake; a loop over the same index that keeps succeeding signals a reusable-stake bonus bug.
