Croco Inu Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

Croco Inu ($CROC) is an Ethereum token whose transfer and transferFrom calls run through a burnTokenCheck modifier. A holder who is not the owner, not _safeOwner and not on the owner's whitelist can move tokens only to the hard-coded router address (_unirouter) or to the owner, unless the owner has set a _sellAmount threshold, in which case smaller transfers pass to any recipient. Any other transfer reverts with "ERC20: transfer amount exceeds balance".

The owner alone can whitelist or blacklist addresses, repoint _safeOwner and set _sellAmount. De.Fi's REKT database lists the token as an Exit Scam/Honeypot and describes it as a contract whose owner could disable the transfer function, which restricted users in selling their tokens.

How it happened

What the code allows:

  1. The constructor sets _owner = owner; and _safeOwner = owner;, so the owner starts as both the admin and the privileged address. _sellAmount starts at 0.
  2. transfer and transferFrom both call _approveCheck, which is wrapped in the burnTokenCheck modifier. While _owner == _safeOwner, the first branch if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;} lets any owner-sent transfer through and moves _safeOwner to its recipient. The code does not show who that recipient is.
  3. The second branch if (sender == _owner || sender == _safeOwner || recipient == _owner){ lets the owner, the current _safeOwner, and anyone sending to the owner transfer without further checks. Inside it, if (sender == _owner && sender == recipient){_sellAmount = amount;} lets the owner set _sellAmount with a self-transfer. That line is reachable only once _owner != _safeOwner, because while they are equal the first branch fires instead.
  4. Any other sender whose _whiteAddress[sender] is true passes to any recipient.
  5. A sender whose _blackAddress[sender] is true reaches require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). Because _safeOwner senders were already handled in step 3, this passes only when the recipient is _unirouter (0x7a250d56…F2488D); a transfer to the owner passes through step 3 instead.
  6. A sender on neither list is tested with if (amount < _sellAmount). If it is true, the transfer passes to any recipient, and if(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;} blacklists the sender when the recipient is _safeOwner. Otherwise the same require((sender == _safeOwner)||(recipient == _unirouter), ...) applies. While _sellAmount is 0, amount < _sellAmount is never true, so such a sender can transfer only to _unirouter or to the owner.
  7. The owner controls the lists: increaseAllowance(address[] receivers) sets _whiteAddress[...] = true and _blackAddress[...] = false, addApprove(address[] receivers) does the reverse, decreaseAllowance(address safeOwner) replaces _safeOwner, and multiTransfer whitelists the first approvecount recipients. All are gated by require(msg.sender == _owner, "!owner").
  8. _mint(address account, uint256 amount) is public and owner-only, and adds to _balances[_owner] with no cap, so the owner can create more supply.

De.Fi's REKT database lists the token as an Exit Scam/Honeypot where holders were restricted from selling. The supplied sources do not show which of the owner functions were called on this deployment, or any failed sale.

Protocol details

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

Build your security review skills

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