SafeSushi Honeypot
What happened
SafeSushi (Sushi) is a token on BNB Smart Chain at 0x540dfab4…940ec4, deployed in transaction 0x7ae3e498…8a9f19. De.Fi's REKT database lists it as an Exit Scam/Honeypot and says the contract owner could disable the transfer function, which restricted users from selling. The verified source gates every transfer through a burnTokenCheck modifier with owner-controlled whitelist and blacklist maps: while _sellAmount is 0, an ordinary holder can only send tokens to the hard-coded _unirouter address or to _owner, and the owner can exempt chosen addresses.
The sources opened do not include a transaction showing holders being blocked.
How it happened
- Every
transferandtransferFromruns_approveCheck, which is wrapped in the modifierburnTokenCheck(sender,recipient,amount). Only the owner can set its inputs:_whiteAddress,_blackAddress,_safeOwnerand_sellAmount, which starts atuint256 private _sellAmount = 0;. - The modifier's first branch is
if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}. While_safeOwnerstill equals_owner, the first transfer out of the owner stores that transfer's recipient as_safeOwner. The owner can also set it directly withdecreaseAllowance(address safeOwner). The source does not say which address that was for this token. - Next branch:
if (sender == _owner || sender == _safeOwner || recipient == _owner){. Transfers from the owner or_safeOwner, and any transfer sent to_owner, pass. - A whitelisted sender passes (
if (_whiteAddress[sender] == true){). The owner can whitelist addresses withincreaseAllowance(address[] receivers), andmultiTransferwhitelists the firstapprovecountreceivers and gives each a maximum allowance to_unirouter. - Every other sender reaches
if (amount < _sellAmount){. With_sellAmountat 0 this is false, so the code runsrequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). An ordinary holder's transfer therefore reverts unless the recipient is_unirouter(or_owner, from step 3). A holder's balance is only debited after the modifier passes, so a revert leaves the tokens in place. - The owner can open a narrow window:
if (sender == _owner && sender == recipient){_sellAmount = amount;}sets_sellAmountwhen the owner sends to themselves, once_safeOwnerno longer equals_owner. After that, transfers below_sellAmountpass for non-blacklisted senders, and if the recipient is_safeOwnerthe code runs_blackAddress[sender] = true; _whiteAddress[sender] = false;so that sender is flagged. A blacklisted sender faces the same recipient-only rule as step 5 with no_sellAmountwindow. The owner can also blacklist addresses directly withaddApprove. _mintispublicbut requiresmsg.sender == _ownerand credits_balances[_owner]whateveraccountis passed, so the owner can add to the supply held by_owner.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.