Rug pull red flags: what to check before you buy

Rugpull redflags
Table of Contents

Six things decide whether a token can be taken from you, they are all readable on-chain in about ten minutes, and every one of them is the same question wearing a different hat. Who kept a key, and what does the key open?

A tenancy makes the point better than a token does. You can read the lease, count the locks and check the deposit sits in a protection scheme, and none of it settles anything if the landlord kept a key to the front door and the agreement lets him use it. The lock is not the question. The key is.

Quick answer

A rug pull is when the people behind a token take the value out of it and leave holders with something unsellable or worthless. The red flags that matter are all privileges: an unrenounced mint authority, an upgradeable contract with a single owner, unlocked or briefly locked liquidity, a pause or blocklist or uncapped fee, unverified source code, and a supply concentrated in a few wallets. Each one is readable on a block explorer before you buy. None of them is proof of intent, and the most common rug pulls use no malicious code at all.

Most rug pulls are not a code problem {#not-a-code-problem}

Start with the uncomfortable half, because every checklist skips it.

CRPWarner, in IEEE Transactions on Software Engineering, hand-collected 103 real rug pull events, categorised 93 of them, and sorted those into two families: contract-related, “which occur through malicious functions in smart contracts”, and transaction-related, “which occur through cryptocurrency trading without the use of malicious functions”. Their six types, in their own words:

Family Type The paper’s definition Events
Contract Hidden Mint Function “Exist a mint function to generate any number of tokens to any address.” 13
Contract Limiting Sell Order “Exist a mechanism to restrict users from selling tokens.” 12
Contract Leaking Token “Exist a mechanism to leak token from other users without permission.” 11
Transaction Dumping Cryptocurrency “Sell off a large number of cryptocurrency suddenly.” 34
Transaction Withdrawing Liquidity “Withdraw liquidity and steal almost all the valuable assets in the pool.” 18
Transaction Abandoning Project after Funding “Abandon the project and abscond without delivering on their promises.” 5

Count the columns. 57 of the 93 categorised events were transaction-related, meaning no malicious function was needed. A contract review cannot find those, because there is nothing wrong with the contract. What it does find is the other 36, and there are plenty in the wild: run against 13,484 real Ethereum token contracts, the same detector “successfully detected 4168 smart contracts with malicious functions”, roughly three in ten. For scale, Trade or Trick? in ACM POMACS found “roughly 50% of the tokens listed on Uniswap are scam tokens”, taking “at least $16 million from 39,762 potential victims”.

A transaction-related rug is not subtle once it happens, and you can read one rather than take anyone’s word for it. In a single transaction on 29 October 2021, block 13511945, AnubisDAO’s pool tokens were burned and 13,556.37 WETH left the Balancer Vault to one address. No exploit, no backdoor, no clever function. Somebody held the pool tokens and redeemed them.

The red flags, and what each one actually proves {#the-red-flags}

This is the table to lift. The fourth column is the one no checklist gives you.

Red flag Where you read it What it proves What it does not prove
Source not verified The explorer’s Contract tab shows bytecode only Nothing can be reviewed, by you or anyone An unverified contract is not automatically malicious. It is unreadable, which is worse for you and better for them
Mint authority still live EVM: any path reaching _mint behind an owner or role check. Solana: the mint account’s mint_authority field Supply can grow, your share can be diluted, and the new supply can be sold into the pool A live mint is normal for a stablecoin or a rewards token. The question is who holds it and what caps it
Upgradeable proxy EIP-1967 slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc holds the implementation, slot 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 holds the admin. Read both with eth_getStorageAt The code you reviewed can be replaced by code you have not seen Upgradeability is standard practice. A proxy behind a timelock is not the same thing as a proxy behind one private key
Liquidity unlocked, or locked briefly The LP token balance and its holder. If a locker is used, read the unlock date, not the badge Value can leave the pool when the lock ends A lock does not cover supply held outside the pool, and it does not stop the pool being drained by selling into it
Pause, blocklist, or an uncapped fee Search the verified source for owner-guarded setters. On Solana, the mint’s freeze_authority Your exit can be closed after you enter A pausable transfer is an ordinary incident control. The tell is a switch with no ceiling and no notice
Supply in a handful of wallets The explorer’s Holders tab, excluding the pool, the locker and burn addresses A small number of parties can end the market on their own Concentration is normal at launch. What matters is whether vesting is enforced on-chain

Two of those rows are Solana-specific and are usually skipped, which is odd given where most of this now happens. The SPL Token documentation is unambiguous. On minting: “As long as a Mint contains a valid mint_authority, the Mint is considered to have a non-fixed supply”, and “The SetAuthority instruction can be used to irreversibly set the Mint’s authority to None, rendering the Mint’s supply fixed.” On freezing: “If a Mint’s freeze_authority is set to None then account freezing and thawing is permanently disabled.” A live freeze authority means somebody can make your token account unusable, which is a sell gate under another name.

The balance shifts by chain. A 2026 measurement study of rug pulls on Solana, still a preprint, puts it this way: “Unlike Ethereum-based Rug Pulls, which often rely on malicious smart-contract logic, Solana’s unified SPL Token program shifts fraudulent execution toward on-chain behavioral manipulation.” Its three observed patterns are freeze authority abuse, liquidity withdrawal and pump-and-dump.

The scanners are useful, and they document where they stop

Automated checkers are the fastest thing available and worth running first. What they do not put on the front of the report is how much of the answer depends on the contract being readable at all.

GoPlus states it in its own API reference. Several risk fields carry the note “Will not be returned if is_open_source is 0″, so a closed-source contract does not fail those checks, it skips them. Same for proxies: “When the contract is a proxy, other risk items may not be returned.”

An empty risk field and a clean risk field look identical on a dashboard. They are opposite findings.

That reference is also the best plain list of what the industry checks for, and one entry deserves reading twice. hidden_owner: “Hidden ownership is used by developers to maintain ownership ability even after abandoning ownership, and is often an indicator of malicious intent.” Another, owner_change_balance, returns 1 “if the contract owner can change token holder balances”. There are contracts in which the owner can edit what you hold.

Reading a real one: the Squid Game contract {#squid}

All of that is abstract until you open something, so open the most famous one.

The SQUID token contract on BNB Smart Chain, 0x87230146E138d3F296a9a77e497A2A83012e9Bc5, is verified. Green tick, published source, readable. And what you can read is almost entirely proxy plumbing, because the contract is an EIP-1967 proxy. Its two slots say so:

# implementation slot
curl -s -X POST https://bsc-dataseed.binance.org/ -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"eth_getStorageAt","params":[
  "0x87230146E138d3F296a9a77e497A2A83012e9Bc5",
  "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
  "latest"],"id":1}'
# -> 0x000000000000000000000000f41bd7d47c8589662e852ace26c99623fac9c05f

# admin slot: swap in 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
# -> 0x0000000000000000000000006bdb3b0fd9f39427a07b8ab33bac32db67eb4e38

A storage slot holds 32 bytes, so an address comes back left-padded with 24 zero bytes. The last forty hex characters are the address. Both reads were run on 2 September 2026 and both still return those values.

Two things follow. The implementation, 0xf41bd7d4..., holds 13,851 bytes of code and is not verified, so the logic deciding what a transfer did was never published. And the admin slot holds a single address that could swap that implementation, through a function the source calls approveTo, guarded by a modifier named ifSir rather than anything containing the word admin.

Pull that unverified implementation with eth_getCode and its revert strings are still legible in plain ASCII. Among the ordinary OpenZeppelin messages sit three that are not ordinary: SQUID: caller is not the masterChef, SQUID: caller is not the dev, and SQUID: caller is not the end. Three custom role gates, in code nobody could read, behind a verified badge.

That is what “verified” bought, and finding it takes two node calls.

The same three powers, in code {#in-code}

Here is what an unbounded set of switches looks like written out. Nothing in it is unusual, and that is the point.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Minimal ERC-20 surface, trimmed to the three switches that matter.
contract Token {
    mapping(address => uint256) public balanceOf;
    uint256 public totalSupply;
    address public owner;

    uint256 public sellFeeBps;          // basis points taken on a sell
    mapping(address => bool) public blocked;

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    constructor() {
        owner = msg.sender;
    }

    // 1. No cap. The owner can print supply until your holding is worthless.
    function mint(address to, uint256 amount) external onlyOwner {
        totalSupply += amount;
        balanceOf[to] += amount;
    }

    // 2. No ceiling. 10000 basis points is 100%, so this setter can take the whole trade.
    function setSellFee(uint256 bps) external onlyOwner {
        sellFeeBps = bps;
    }

    // 3. No list, no notice. One call and an address can no longer transfer.
    function setBlocked(address account, bool state) external onlyOwner {
        blocked[account] = state;
    }
}

Two of those three powers take a number, so they can carry a ceiling the setter enforces. Nothing is deleted below, it is bounded.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// The same powers, bounded. Nothing here is deleted, it is capped.
contract BoundedToken {
    uint256 public constant MAX_SUPPLY = 1_000_000_000e18;
    uint256 public constant MAX_SELL_FEE_BPS = 300;   // 3%, and the setter enforces it

    mapping(address => uint256) public balanceOf;
    uint256 public totalSupply;
    address public owner;                              // a timelock or multisig, not an EOA
    uint256 public sellFeeBps;

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    constructor(address owner_) {
        owner = owner_;
    }

    function mint(address to, uint256 amount) external onlyOwner {
        require(totalSupply + amount <= MAX_SUPPLY, "cap");
        totalSupply += amount;
        balanceOf[to] += amount;
    }

    function setSellFee(uint256 bps) external onlyOwner {
        require(bps <= MAX_SELL_FEE_BPS, "fee too high");
        sellFeeBps = bps;
    }
}

A fee that cannot exceed 3% because the setter refuses is a different object from one that can go to 99%. Both read as “the owner can change the fee” in a summary. Only one of them can take your exit.

The blocklist is the interesting omission. A blocklist has no number to cap, so bounding it is not a ceiling in the code, it is who holds the key: the owner above is annotated as a timelock or a multisig rather than one wallet, so the call is visible before it lands. When a power cannot be capped, the only remaining control is making its use slow and public.

Four things treated as proof of safety that are not {#four-myths}

Three of the four below are answered by a party writing against its own interest, which is the strongest kind of source on this question, and the fourth by a public court filing.

“Ownership is renounced”

Renouncing sets the owner to the zero address, and OpenZeppelin’s own Ownable says exactly what that buys: “Leaves the contract without owner. It will not be possible to call onlyOwner functions.”

Read the scope. It disables functions guarded by onlyOwner. It does nothing to a role under a different access-control scheme, nothing to a hardcoded privileged address, and nothing to a proxy admin, which is a separate slot with a separate holder. A renounced token behind an upgradeable proxy can have its logic replaced tomorrow. And the gesture is used deliberately: the Solana study records operators who “may voluntarily renounce LP tokens or choose not to use the account freeze function to present the project as decentralized and fairly launched, thereby building user trust”.

“The liquidity is locked”

The clearest disproof came from a courtroom. In SEC Litigation Release No. 25888 (1 November 2023), the Commission alleged that in marketing SafeMoon its creator “assured investors that funds were safely locked and could not be withdrawn by anyone, including the Defendants”, and that in fact “large portions of the liquidity pool were never locked”. The token “skyrocketed in price by more than 55,000 percent” and then fell by nearly half “when the public learned, on April 20, 2021, that SafeMoon’s liquidity pool was not locked as claimed”. SafeMoon’s chief executive was convicted by a jury in May 2025.

A lock can also be entirely real and still not help, and UNCX’s own FAQ says so: “Locking 100% of the liquidity does not mean however that your funds are safe.” The mechanism is in the same document and it is the part most people have backwards. What gets locked is the LP token, not the assets: “ETH/BNB/etc. is not ‘locked’ in the liquidity pool, but the LP token (representing the ratio of tokens in a pair) is locked.” Sell a large unlocked supply into the pool and the pool fills with the token and empties of the paired asset. In their words, “The amount of locked LP tokens remains the same and are still locked, but their value is extremely low.”

The lock held perfectly. The pool is empty. And the correlation runs the opposite way to the folklore: a study of Uniswap V2 listings found “90% of tokens using locking contracts tend to become a rug pull or a malicious token eventually”. A lock tells you somebody wanted you reassured. The same FAQ adds, in its own brackets, “UNCX Network is not an audit company.”

“The contract is verified”

Etherscan could not be more direct. On interacting safely with contracts: “‘Verified’ does not mean the contract is safe to interact with or that it has been audited. It only confirms that the published source code corresponds to what is running on the blockchain.” And at the foot of the same page: “Etherscan helps you inspect and explore onchain data, but it does not audit or guarantee the safety of contracts.”

Verification proves the source you are reading is the code that is running. Somebody still has to read it, and as SQUID shows, a verified proxy can publish everything except the part that matters.

“It has been audited”

An audit reviews specific code at a specific commit. It does not hand anyone’s private keys to the auditor, and it cannot stop a person who controls a privileged function from using it. A report saying “the owner can mint without limit” is an accurate audit of a contract that can be rugged. And it expires quietly, because an upgradeable contract can move off the audited commit the day after publication, which is the whole reason an audit has a shelf life.

So read the report rather than the badge. Check the audited commit against what is deployed, check the scope covers the contract holding the money, and check the findings were fixed rather than acknowledged. Fidesium’s audit portfolio is published in full for that reason, 23 reports across 16 protocols on EVM chains and Solana, each minted as an on-chain record so the result can be checked instead of claimed.

If you are the team rather than the buyer {#if-you-are-the-team}

Every detector above reads capabilities, not intent, and four things serious protocols ship for good reasons will trip them: a treasury-funding transfer fee, pausable transfers as an incident control, a blocklist a regulated token may be obliged to hold, and an upgradeable proxy because the contract is expected to change. Ship any of them and a scanner may warn, an aggregator may show a risk badge, and the first person to notice will post the screenshot rather than the source.

The answer is not to strip the features out. It is to bound them and make the bounds legible.

  • Verify the source, and re-verify after every upgrade. An unverified implementation behind a verified proxy is the worst look in this category.
  • Put the ceiling in the setter, not in the documentation. A fee capped at 3% by require is checkable. A fee capped at 3% by a blog post is not.
  • Move the owner behind a timelock or a multisig, so a change is visible before it lands rather than after.
  • Document every privileged function in plain language, including what it cannot do.
  • Publish the audit, and publish the re-audit when the code changes.

That last one is the part that decays, which is why continuous scanning runs on every commit and post-deployment monitoring uses detectors tuned to a protocol’s own logic rather than generic thresholds. Fidesium’s manual smart contract audits are line-by-line human review by the core team, chain agnostic with an EVM specialism, covering logic and economic risk, with two rounds of fix verification included. They start at $5,000 and the reports are public.

None of it makes a contract safe. What it does is put your contract’s powers in writing, with their ceilings, before somebody else describes them for you. For the project-level half, communication, delivery, vesting and governance, our earlier piece on when a rug pull is not a rug pull covers that ground.

Frequently asked questions {#faq}

What is a rug pull?

A rug pull is when the people behind a token take the value out of it and leave holders with something unsellable or worthless. Research in IEEE Transactions on Software Engineering splits it in two: contract-related rug pulls, which use a malicious function such as a hidden mint or a sell restriction, and transaction-related rug pulls, which use ordinary trading to dump a retained supply, withdraw the liquidity, or abandon the project after funding.

What are the biggest red flags of a rug pull?

Six, and all of them are privileges somebody kept: source code that is not verified, a mint authority that is still live, an upgradeable contract whose admin is a single private key, liquidity that is unlocked or locked only briefly, an owner who can pause transfers or blocklist addresses or raise the sell fee without a ceiling, and a supply held in a handful of wallets.

Can a token still be a rug pull if liquidity is locked?

Yes, in three ways. The lock may not exist as described, which is what the SEC alleged about SafeMoon, saying “large portions of the liquidity pool were never locked”. It may cover only part of the supply, leaving the rest to be sold into the pool. Or it may work perfectly while the pool is drained anyway, because what is locked is the LP token rather than the assets. UNCX, a lock provider, says so itself: “Locking 100% of the liquidity does not mean however that your funds are safe.”

Does renounced ownership mean a token cannot rug?

No. OpenZeppelin’s Ownable documents renouncing as leaving the contract without an owner so that “it will not be possible to call onlyOwner functions”. That is the whole scope. It does not disable a proxy admin, a role under a different access-control scheme, or a hardcoded privileged address, and a 2026 study of Solana rug pulls records operators renouncing to “present the project as decentralized and fairly launched, thereby building user trust”.

Is a verified contract a safe contract?

No. Etherscan states that “‘Verified’ does not mean the contract is safe to interact with or that it has been audited. It only confirms that the published source code corresponds to what is running on the blockchain.” A proxy can also be verified while the implementation behind it is not, which is what the Squid Game token did: the proxy carries the tick, and the 13,851 bytes of logic it delegates to were never published.

Are audited projects safe from rug pulls?

No. An audit documents the privileges in the code: unbounded mints, uncapped fee setters, transfer gates, one-key proxy admins. It cannot take away keys the team holds, and it describes one commit, so an upgradeable contract can move off the audited code the day after the report. Read the report, check the audited commit against what is deployed, and check the findings were fixed rather than acknowledged.

How do I check a Solana token for a rug pull?

Read the mint account’s two authority fields. The SPL Token documentation states that “as long as a Mint contains a valid mint_authority, the Mint is considered to have a non-fixed supply”, and that SetAuthority can “irreversibly set the Mint’s authority to None, rendering the Mint’s supply fixed”. Then read freeze_authority, because a live one means token accounts can be frozen, which closes your exit. Then check holder concentration excluding the pool. On Solana the mechanism is usually behavioural rather than code-level, so trading history matters more here than on Ethereum.

Can a rug pull checker be wrong?

Yes, in both directions. GoPlus documents that several of its risk fields “will not be returned” when a contract is closed-source, and that when a contract is a proxy “other risk items may not be returned”, so a missing check and a passed check look identical on a dashboard. In the other direction, a legitimate token with a transfer fee, a pause function or an upgradeable proxy gets flagged by tools that read capability rather than intent.

Share:

More Posts

Scan your project now for free

Tell us your security needs