OBB Token Rug Pull

Reported loss $156K
Rugpull

What happened

OBB is a BEP20 token (contract 0xd23b64db…034c30) traded against USDT on PancakeSwap. Its verified code makes selling the exception rather than the rule: _transfer reverts whenever Legaladdress returns true, and for an ordinary wallet that is not the deployer or the pair it returns true unless an admin has granted that wallet a sell budget with setMdMap. Buying from the pair and anything the deployer address sends pass the check, so the code lets the deployer trade freely while holders are locked in.

CertiK's Skynet alert of 2023-02-09 reported that OBB had dropped 98% and that the deployer removed about $156k of liquidity; De.Fi's REKT database lists the incident as an exit scam/rugpull of 156,063 USD. The live listing says the funds were removed directly from the OBB/USDT pool, sent to another EOA and swapped for other tokens. The listed scammer address is 0xb54f89f5…e9a3fb, which is also the address that deployed the contract, and the liquidity removal transaction is 0x8375829b…70d5d0.

The contract does not control the liquidity itself, and the evidence opened here does not show whether any holder's sell was actually blocked.

How it happened

  1. At deployment the constructor mints the whole supply to the deployer, records that address as _ca and gives it the admin role: _ca=_msgSender(); and _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());.
  2. Buys from the pool are allowed. In Legaladdress the pool address _usdtPair is excluded by if(from!=_da && from!=_usdtPair && from!=_ca){, so a transfer from the pair falls through to return false; and is not reverted.
  3. Sells are blocked by default. For any other non-contract sender sending to the pair, uint256 _accc=_mdmap[from]; is zero, so if(_accc == 0){ returns true. _transfer then reverts with require(Legaladdress(from,to,amount)!=true);.
  4. Wallet-to-wallet transfers are blocked as well: the else branch of the if(to==_usdtPair) test is return true;, which reverts the same way.
  5. Only the admin can open an exit. setMdMap(address user,uint256 amount) is onlyRole(DEFAULT_ADMIN_ROLE) and sets the sell budget, setBotfrom and setPair use the same role, and the deployer address _ca is never checked at all. The code lets the deployer decide who may sell.
  6. What was reported: CertiK recorded a 98% price drop with the deployer removing about $156k of liquidity, and De.Fi's listing gives the removal transaction above. The pool's LP tokens are not held by this contract, so the removal itself is not a function of the token code.

Protocol details

Classification Token
Protocol Type Exit Scam/Rugpull
Affected asset / contract OBB

Build your security review skills

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