PenginFinance Token Rug Pull
What happened
PenginToken is a MasterChef-style governance token whose owner can mint without limit and whose transfers are locked until the owner calls unlock(). While isTransferable is false, _beforeTokenTransfer only allows transfers where the sender or the recipient is the owner, so ordinary holders cannot move or sell tokens to a liquidity pair. The same check also covers mints, so before unlock() the owner can mint only to the owner address; the mint function itself has no cap.
De.Fi's REKT database lists PENGIN as an exit scam/rug pull on BNB Smart Chain, citing a BscScan page for the deployer address 0xdCbCc7cC…E0E4c6; the source alone does not show whether the owner minted, kept the lock on, or removed liquidity.
How it happened
- The token starts with no supply:
constructor() ERC20("PenginFinance Token", "PENGIN") {}. New tokens come only frommint, and the deployer becomes theOwnableowner. - The owner can mint any amount:
function mint(address _to, uint256 _amount) public override onlyOwner { _mint(_to, _amount); ... }. No maximum supply is enforced anywhere in the contract. Because_mintcalls_beforeTokenTransfer(address(0), account, amount), the lock in step 3 applies to mints too: untilunlock()is called,mintcan only target the owner address. A code comment says the owner is meant to be the MasterChef (farming) contract, which is a deployment choice the source does not enforce. - Transfers start locked:
bool public isTransferable;defaults to false, and_beforeTokenTransferrunsif (isTransferable == false) { require(from == owner() || to == owner(), "locked"); }on every transfer, mint and burn. - While locked, a holder's transfer to a pair or to another holder reverts with "locked" unless the owner is the sender or recipient, and a mint to any other address reverts the same way. Only the owner can end the lock, with
function unlock() public override onlyOwner { isTransferable = true; }, and there is no function that re-locks. Afterunlock(), the owner can mint any amount to any address. - The owner can pass these powers to another address with
transferOwnership(address newOwner)or give them up withrenounceOwnership(); a read of the contract on 2026-09-30 returns an owner (0x85cd1f59…e04c49) different from the deployer, but the transaction that changed it was not opened. - What the owner actually minted, whether
unlock()was called, and whether holders were prevented from selling are not shown by the source; the rug-pull label comes from De.Fi's listing.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.