Tribe Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

Tribe (TRIBE, Ethereum, contract 0xc55b6b97…56d685) routes every transfer and transferFrom through a burnTokenCheck modifier that treats senders differently. In the default state (_sellAmount is 0), a holder who is neither the owner nor on the owner's whitelist can only send tokens to the hard-coded _unirouter address or to _owner; any other transfer reverts with a misleading 'transfer amount exceeds balance' message. A sell that sends tokens to a pair address would therefore fail for such a holder, unless the pair is itself one of the exempt addresses, which the code does not settle.

De.Fi's REKT database lists the token as an Exit Scam/Honeypot, stating that the owner could disable the transfer function, which restricted users in selling their tokens. The code shows what the owner can do; the sources opened do not show which addresses were whitelisted, blacklisted or exempt on-chain, or any resulting losses.

How it happened

  1. The constructor sets _owner = owner; and _safeOwner = owner; and mints the initial supply to _owner. _sellAmount starts at 0 (uint256 private _sellAmount = 0;).
  2. transfer and transferFrom both call _approveCheck, which is wrapped by burnTokenCheck(sender,recipient,amount).
  3. While _safeOwner still equals _owner, the first transfer sent by _owner runs _safeOwner = recipient; and goes through. After that, a transfer passes when sender == _owner || sender == _safeOwner || recipient == _owner.
  4. A sender outside that group passes only if _whiteAddress[sender] == true. Otherwise the code reaches require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");, either because the sender is in _blackAddress or because amount < _sellAmount is false. In those branches sender == _safeOwner is already ruled out, so only a transfer to _unirouter passes. Because _sellAmount starts at 0, amount < _sellAmount cannot hold until the owner sets it.
  5. Owner-only functions change who is exempt, under names that do not describe them: increaseAllowance(address[] receivers) sets _whiteAddress[receivers[i]] = true; and clears the blacklist entry; addApprove(address[] receivers) sets _blackAddress[receivers[i]] = true; and clears the whitelist entry; decreaseAllowance(address safeOwner) sets _safeOwner = safeOwner;; multiTransfer whitelists the first approvecount receivers and approves _unirouter for the maximum amount over their tokens.
  6. _sellAmount is set when _owner transfers to itself: if (sender == _owner && sender == recipient){_sellAmount = amount;}. Once it is nonzero, a non-listed sender's transfer below that amount is allowed, and if its recipient is _safeOwner the sender is added to _blackAddress before the transfer runs.
  7. No function other than the constructor assigns _owner, and there is no renounce function, so these powers stay with that address. _mint is public but requires msg.sender == _owner and credits _balances[_owner], so the owner can also create more supply.

Protocol details

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

Build your security review skills

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