ChainGPT Rug Pull
What happened
This record covers a token named ChainGPT (CGPT) at BSC contract 0x6e70ee54…29eBBF, the contract CertiK's alert flags. ChainGPT's documentation lists a different contract, 0x9840652D…f00f98, as the native CGPT token on BSC.
The source routes transfer and transferFrom through delegatecall to a replaceable proxyAddr, so the real transfer rules are not in the verified files: whether and how the blacklist is enforced, and any burn ratio or reward logic, cannot be seen in the source, and the proxy's source was not available. The owner can mint any amount with mint and add addresses to a blacklist, and any whitelisted address, which includes the deployer, can change proxyAddr to a different contract. There is no renounceOwnership, and transferOwnership rejects the zero address, so ownership cannot be renounced to the zero address; the owner can still transfer it to another address. On-chain owner() is 0xd9618606…1f1918 (read 2026-09-30).
CertiK's alert of 2023-04-12 reports a large liquidity removal on this contract, about $76K removed by the deployer. De.Fi's REKT database lists the incident as an exit scam/rug pull of about 82k USD on BSC in which the deployer removed a significant amount of liquidity and sold the token, for a drop of about 90% from the initial price.
from De.Fi's listing: address named as responsible 0xd9618606…1f1918; liquidity removal transaction 0x12c1a6cc…07c005.
How it happened
- The constructor puts the 1,000,000,000 supply in the deployer's balance and whitelists the deployer:
_balances[_msgSender()] = _totalSupply;and_whitelist[_msgSender()] = true;. - Transfers are not handled in this file.
transferruns(bool success, ) = proxyAddr.delegatecall(abi.encodeWithSignature("transfer(address,uint256)",recipient,amount));andtransferFromdoes the same, so the rules run inside whatever contractproxyAddrpoints to, with write access to this token's balances. The proxy source is not in the verified files, so its sell and burn rules cannot be traced. - The target can be swapped:
function setProxyAddr(address _addr) publicrequires_whitelist[msg.sender] == trueand then runsproxyAddr = _addr;. The deployer is whitelisted at construction andaddWhitelist(onlyOwner) can add more addresses. - Supply is not fixed:
function mint(address account, uint256 amount) onlyOwner public virtual returns (bool)calls_mint(account, amount);with no cap. - A blacklist exists:
addBlacklist(address[] memory accounts) public onlyOwnersets_blacklist[accounts[i]] = true;. Reading it is restricted, sincecheckBlacklistbeginsrequire(_whitelist[msg.sender] == true, "No permission.");, so holders cannot query their own status. The verified file does not enforce the blacklist anywhere, and the proxy source was not seen, so where or whether it is enforced is not visible. - Ownership cannot be renounced to the zero address: there is no
renounceOwnership, andtransferOwnershiphasrequire(newOwner != address(0), ...). The owner can still transfer ownership to any other address. - What was reported: CertiK says about $76K was removed by the deployer on 2023-04-12, and De.Fi's listing gives about 82k USD. Removing liquidity does not require any of the functions above, and no opened transaction shows the owner calling
mint,addBlacklistorsetProxyAddr, so these steps describe what the code allows.
Protocol details
Evidence
- report @CertiKAlert incident report twitter.com
- report CertiK Alert post on ChainGPT (CGPT) liquidity removal x.com
- transaction bscscan.com transaction 0x12c1…c005 bscscan.com
- address ERC20Token (ChainGPT/CGPT) verified source on BscScan bscscan.com
- address bscscan.com address 0xd961…1918 bscscan.com
- analysis ERC20Token on Sourcify (match) repo.sourcify.dev
- analysis CGPT Utility Token (ChainGPT documentation) docs.chaingpt.org
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.