# Stepp2p: double-spend in cancelSaleOrder and modifySaleOrder

Stepp2p sale order logic double-refunds on cancel then modify, letting attacker flash-loan USDT and drain 43k USD.

- Payout: Real-world hack
- Severity: high
- Program: Stepp2p
- Credited: DeFiHackLabs
- Disclosed: 2025-07-20
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2025-07/Stepp2p_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20250720-stepp2p
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm technique:chained vuln:accounting-error vuln:business-logic vuln:flash-loan

**Target:** BSC smart contract sale order functions
**Root cause:** cancelSaleOrder and modifySaleOrder on the same saleId both transfer funds back to the seller, so the same deposit is refunded twice.
**Steps:**
1. Flash loan 50,000 USDT from PancakeV3 USDC/USDT pool via `flash()`.
2. In callback, read Stepp2p's USDT balance and `approve` it.
3. Call `createSaleOrder(amount)` to deposit, receiving `saleId`.
4. Call `cancelSaleOrder(saleId)` — refunds deposit.
5. Call `modifySaleOrder(saleId, amount, false)` — refunds deposit again.
6. Repay flash loan plus fee; keep the duplicated funds.
**Exploitation:** Attacker flash-borrows 50k USDT, deposits into Stepp2p via createSaleOrder, then triggers both cancelSaleOrder and modifySaleOrder on the same order to receive two refunds for one deposit, repays the loan and pockets the excess.
**Insight:** When a contract has both cancel and modify functions on the same order ID, check whether each independently releases escrowed funds without invalidating the order state — a classic double-refund path.
