Excavator Honeypot

Reported loss Not disclosed
BNB Chain
Honeypot

What happened

De.Fi's REKT database lists Excavator (EXC, BNB Smart Chain contract 0x6a872788…d3562b) as an exit scam/honeypot, noting that the contract owner could disable the transfer function, which restricted users in selling their tokens. In the verified source, a modifier on _transfer records the recipient of the first transferFrom in a variable named nxOwner and from then on reverts any transfer to that address unless the sender is _owner or _leaveowner. If that first recipient is the liquidity pool, ordinary holders can receive tokens from it but cannot sell back to it.

renounceOwnership clears only _owner; the second privileged address _leaveowner is not cleared, so the exemption and the owner-only functions stay with the deployer address 0x590A634D…F704aa. No loss figure is given by De.Fi.

How it happened

  1. The Ownable constructor stores the deployer in two variables: _owner = msgSender; and _leaveowner = msgSender;. The Excavator constructor assigns the whole supply to the deployer: _balances[msg.sender] = _totalSupply;.
  2. transfer calls _transfer(..., false) and transferFrom calls _transfer(..., true). Both run the modifier PancakeSwabV2Interface(sender, recipient, fromTransfer).
  3. The modifier: if(from != address(0) && nxOwner == address(0) && fromTransfer) nxOwner = to; else require((to != nxOwner || from == _owner || from == _leaveowner), "Order TransferFromMiddleware");. While nxOwner is empty, the first transferFrom is let through and its recipient is stored as nxOwner. Any address that receives that first transferFrom, such as a liquidity pool filled through a router, becomes the blocked recipient.
  4. After that, every transfer whose recipient is nxOwner reverts unless the sender is _owner or _leaveowner. A holder's sell through a router is a transferFrom from the holder to the pool, so it reverts. Buys, where the pool is the sender and the buyer is the recipient, pass the to != nxOwner test.
  5. transferOwnership(address newOwner) does not transfer ownership; it only sets nxOwner = newOwner;. It is restricted by onlyOwner, which accepts _owner or _leaveowner. Pointing nxOwner at an unused address lifts the block, and setting it to the zero address makes the next transferFrom capture a new recipient.
  6. renounceOwnership only sets _owner = address(0);. The _leaveowner variable is untouched, so after renouncing, _leaveowner still passes onlyOwner and still bypasses the sell block.
  7. The fee variables _fee, _feeLiq and _feeHolders are declared but _transfer never reads them; it debits the sender's balance and credits the recipient with the same amount.

Protocol details

Classification Exchange (DEX)
Protocol Type Exit Scam/Honeypot
Affected asset / contract EXC

Build your security review skills

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