French Shiba Honeypot
What happened
French Shiba (USHlBA) is an Ethereum token whose transfer and transferFrom both pass through a burnTokenCheck modifier that treats senders differently. The owner-controlled variables _safeOwner, _sellAmount and two address lists decide whether a transfer reverts, and the revert text ("ERC20: transfer amount exceeds balance") is the one a balance problem would show. Unless the sender is the owner, _safeOwner, whitelisted, or sending to _owner, a transfer is accepted only when the recipient is the hard-coded router address 0x7a250d56…F2488D or the amount is below _sellAmount, which starts at 0.
The owner can whitelist or blacklist addresses and move _safeOwner. De.Fi's REKT database lists the token as an Exit Scam/Honeypot dated 2021-05-12 and says the owner could disable the transfer function, which restricted users in selling their tokens; the listing gives no loss figure. No transaction was opened to show which addresses were listed or what _safeOwner holds.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and_unirouter = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D. It then calls_mintten times;_mintcredits_balances[_owner]whateveraccountis, so the nine calls naming 0xAb5801a7…9aeC9B only change the emittedTransferevents, not that address's balance. - In
burnTokenCheck, while_owner == _safeOwner, any transfer sent by the owner passes and runs_safeOwner = recipient;. This hands_safeOwnerto the first address the owner sends tokens to. - Afterwards a transfer passes unchecked if
sender == _owner || sender == _safeOwner || recipient == _owner; whensender == _owner && sender == recipient, the amount is stored with_sellAmount = amount;. - Any other sender passes if
_whiteAddress[sender] == true. If the sender is blacklisted, or on neither list and the amount is not below_sellAmount, the call runsrequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");, so it only succeeds when the recipient is the router. A transfer into any other address, such as a pair, reverts whatever the sender's balance is. With_sellAmountat its initial 0,amount < _sellAmountnever holds. - When
amount < _sellAmountthe transfer passes, andif(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;}blacklists a sender whose recipient is_safeOwner. - The owner-only functions behind the lists have misleading names:
multiTransferwhitelists the firstapprovecountreceivers and approves the router for the maximum amount,increaseAllowance(address[])whitelists and un-blacklists,addApprove(address[])blacklists, anddecreaseAllowance(address)sets_safeOwner._mint(address,uint256)is public but requiresmsg.sender == _owner, and_ownerhas no setter in the code.
Protocol details
Evidence
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.