Apron Network Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

This Apron Network (APN) token on Ethereum hides a sell gate inside a modifier named burnTokenCheck that runs on every transfer and transferFrom. The owner and one privileged address (_safeOwner) can always move tokens, but any other holder's transfer reverts with a fake "transfer amount exceeds balance" error unless the owner has whitelisted them, the amount is below an owner-set threshold, or the tokens go straight to the Uniswap V2 router. A normal Uniswap sell sends tokens to the pair, not the router, so it fails.

The owner can whitelist, blacklist, change _safeOwner and mint without limit through functions given misleading ERC-20 names, and the contract has no way to give up these powers. De.Fi's REKT database lists APN as an exit scam/honeypot; no loss figure or transaction was found.

How it happened

  1. The first time the owner sends tokens, the recipient becomes _safeOwner: if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}. If that first transfer is the liquidity deposit, the Uniswap pair becomes _safeOwner, so buys (transfers out of the pair) always pass.
  2. Transfers from the owner or _safeOwner, or to the owner, always pass. An owner self-transfer sets the sell threshold: if (sender == _owner && sender == recipient){_sellAmount = amount;}. _sellAmount starts at 0.
  3. Any other sender who is not whitelisted and sends at least _sellAmount hits require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");. A Uniswap V2 sell calls transferFrom(holder, pair, amount), so the recipient is the pair, and the sell reverts with a misleading balance error.
  4. If the owner sets a threshold, a holder can send a smaller amount, but sending it to _safeOwner marks them: if(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;}. Blacklisted senders then face the same router-only require for every amount.
  5. The owner controls the lists through misnamed functions: increaseAllowance(address[]) whitelists, addApprove(address[]) blacklists, decreaseAllowance(address safeOwner) replaces _safeOwner, and multiTransfer whitelists recipients and approves the router for them.
  6. _mint is public and gated only by require(msg.sender == _owner, ...), with no cap, and it credits the owner: _balances[_owner] = _balances[_owner].add(amount);. The contract has no function to change or renounce _owner.

Protocol details

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

Build your security review skills

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