Ethereum SHIBA Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

Ethereum SHIBA (eSHIB) is an Ethereum token, contract 0x8372ede9…b4cc69, whose every transfer and transferFrom runs through a burnTokenCheck modifier. Unless the sender is the owner, the _safeOwner address or a whitelisted address, the transfer reverts unless its recipient is the Uniswap V2 router address 0x7a250d56…F2488D or the owner, and the revert message imitates a balance error. A sell through the router moves tokens to the liquidity pair, so it reverts for ordinary holders.

The owner controls the whitelist, a blacklist, _safeOwner and a public _mint. De.Fi's REKT database lists eSHIB as an exit scam/honeypot in which the contract owner could disable the transfer function, restricting users from selling their tokens. The sources opened here do not show which address _safeOwner held on-chain or any specific holder's failed sell.

How it happened

  1. The constructor sets _owner = owner; and _safeOwner = owner; and mints the whole supply to the owner with _mint(_owner, initialSupply*(10**18));.
  2. Every transfer path calls _approveCheck, which carries the burnTokenCheck modifier. Its first branch, if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, moves _safeOwner to the recipient of the owner's first outgoing transfer. If that transfer is the liquidity deposit (transferFrom(owner, pair, ...)), the pair becomes _safeOwner; the code alone does not show what the on-chain value was.
  3. The owner, _safeOwner, and any transfer to the owner pass: if (sender == _owner || sender == _safeOwner || recipient == _owner). With the pair as _safeOwner, a buy (pair to buyer) passes.
  4. A holder who is not whitelisted or blacklisted reaches the last branch. _sellAmount defaults to 0, so amount < _sellAmount is false and the code runs require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");. A router sell is transferFrom(holder, pair, amount): the sender is not _safeOwner and the recipient is the pair, not _unirouter, so it reverts and the holder's balance is not debited. Wallet-to-wallet transfers revert the same way; only transfers to _unirouter or the owner pass.
  5. The owner can change who passes: increaseAllowance (despite its name) sets _whiteAddress to true and _blackAddress to false, addApprove does the reverse, decreaseAllowance(address safeOwner) replaces _safeOwner, and multiTransfer whitelists its first approvecount recipients and gives each a maximum allowance to _unirouter. All are require(msg.sender == _owner, "!owner"). _mint is public and owner-only and credits _balances[_owner], so the owner can mint more at any time.
  6. A transfer from the owner to the owner (when _owner != _safeOwner) runs _sellAmount = amount;. With _sellAmount above zero, a non-listed holder's transfer of a smaller amount passes, and if the recipient is _safeOwner the holder is added by _blackAddress[sender] = true;, after which only transfers to _unirouter pass. Transfers of _sellAmount or more still revert.

Protocol details

Classification Token
Protocol Type Exit Scam/Honeypot
Affected asset / contract eSHIB

Build your security review skills

Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.