How NFTs works on Solana and what to check as an auditor ?

Lilian CariouLilian Cariou
10 min read

NFTS

Non-Fungible Tokens (NFTs) on solana are SPL Tokens with an associated metadata account, 0 decimals, and a maximum supply of 1.

The Metaplex Token Metadata program is an onchain program that attaches metadata to a token mint (which authority is set to null to ensure the supply never changes), the special thing is that when an NFT is minted, a Metadata account is created (using a PDA derived with the mint address as a seed) that contains fields such as the name, symbol, URI (which points to off-chain JSON metadata), creator addresses, royalties info, whether it’s mutable, and so on. We can interact with the Token Metadata program using the Token Metadata package via Umi, a tool made by Metaplex for working with onchain programs.

The mint account is usually the identifier for the NFT or has a defined ID – its public key is the token’s address. The NFT can be held or hold in any Solana wallet via a Token Account (associated with that mint and the owner’s wallet) like any SPL token.

When real NFTs are minted for a collection, the collection authority signs off to mark those NFTs’ metadata as part of the collection (setting a “verified” flag true, and referencing the collection mint)

Compressed NFTS

Compressed NFTs (cNFTs) are exactly what their name suggests: NFTs whose structure takes up less account storage than traditional NFTs. Compressed NFTs leverage a concept called State Compression to store data in a way that drastically reduces costs.

State Compression is the method of creating a "fingerprint" (or hash) of offchain data and storing this fingerprint on-chain for secure verification. Effectively using the security of the Solana ledger to securely validate offchain data, verifying it has not been tampered with.

These trees are created in a "deterministic" process by taking any piece of data, creating a hash of this data, storing this hash as a leaf at the bottom of the tree, each leaf pair is then hashed together, creating a branch,each branch is then hashed together,continually climbing the tree and hashing adjacent branches together and once at the top of the tree, a final root hash is produced.

This root hash is then stored onchain, as a verifiable proof of all of the data within every leaf.

This method of "compression" allows Solana programs and dApps to use cheap blockchain ledger space, instead of the more expensive account space, to securely store data.

Most of the costs associated with traditional NFTs come down to account storage space. Compressed NFTs use a concept called State Compression to store data in the blockchain’s ledger state, only using the account state to store a “fingerprint”, or hash, of the data. This hash allows you to cryptographically verify that data has not been tampered with.

The SPL State Compression Program exists to make the above process repeatable and composable throughout the Solana ecosystem. It provides instructions for initializing Merkle trees, managing tree leafs (i.e. add, update, remove data), and verifying leaf data.

Source: Solana & Metaplex Foundation

To create Compressed NFTs, we first need to create a Merkle Tree that can store the NFT data. Doing so requires an understanding of several critical parameters:

  • Depth: This represents the number of levels within the Merkle Tree, from the root down to the leaves, where each leaf can be an NFT.

  • Max Buffer Size: Since users on Solana might be modifying multiple NFTs in the same tree at once, we need to be able to support changes to the tree without one change invalidating another. Solana uses a special type of Merkle tree, called a concurrent Merkle tree, to support this. The maxBufferSize effectively sets a changelog for managing updates and changes to the tree's proof.

  • Canopy Depth: The canopy is the number of proof nodes that are cached and stored on the chain. A large canopy helps reduce the number of proofs that must be fetched to verify an NFT. A larger canopy will reduce the number of proofs that need to be fetched (and therefore make it easier for programs to interact with the NFT), but it will also increase the cost of storing the tree on the chain.

  1. Trade State Verification: Ensuring Valid Mint and Ownership in Trades

    Solana NFT marketplaces often use trade state accounts (typically PDAs) to represent a listing or bid, encoding the seller, buyer, NFT mint, and price. A critical security check is verifying that these trade states are valid and match actual ownership and intent. Both the seller’s and buyer’s trade state PDAs should be present and in agreement on the price before a sale is executed. The program must also ensure the NFT is still owned by the seller and that the trade state hasn’t been maliciously reused.

    Example – Metaplex Auction House Exploit: In 2022, a severe flaw was found in the popular Metaplex Auction House contract that let attackers exploit improper trade state verification. The contract failed to verify the seller’s trade state “bump” (an identifier) for validity, checking only that the account was open. An attacker could deliberately keep a seller’s trade state PDA alive (by injecting a small rent payment in the same transaction to prevent its closure) and later reuse it. This meant that even after an NFT had offers up to, say, 80k SOL, an attacker could force-sell it at a much lower previously listed price by reusing the old trade state. In one scenario, a hacker tricked a victim into selling an NFT for only 10 SOL after it had been bid up to 100k SOL.

    Security Check: Marketplaces must verify that both buyer and seller PDAs are fresh and uniquely derived for the current trade. After a sale, those PDAs should be closed or marked invalid so they cannot be reused. Additionally, the program should confirm the seller still owns the NFT (e.g. via the token account) and ideally require the seller’s signature for the listing or sale. This prevents attacks where a stale or forged trade state is used to steal NFTs. The Auction House exploit above was patched by adding proper bump validation and ensuring trade accounts are closed irreversibly

  2. Trade State Verification (nft’s mint and sell ownership)

    Solana programs often employ Program Derived Addresses (PDAs) as authorities or vaults to hold NFTs and escrow funds. It’s essential to use PDAs in a way that scopes access to the intended user or purpose. If not, attackers may perform unauthorized withdrawals by tricking the program’s PDA logic. A common mistake is deriving a PDA with insufficiently unique seeds or without strict verification of those seeds.

    Example – Global PDA Vulnerability: Consider an NFT vault where the program uses a PDA as the vault’s authority, derived only from a token mint. If a user’s NFT sale proceeds are stored in this vault, the program might allow a withdrawal instruction that uses the PDA to sign out the funds. However, if the PDA seed is just the mint, any other account that can derive the same PDA (for the same mint) could potentially invoke the withdrawal. In a real instance, a Solana program used a mint-based PDA for a vault, and it turned out an attacker could create a different account (e.g. a fake “pool”) with the same mint to invoke the PDA authority. This meant one user could withdraw another user’s funds because the PDA did not uniquely tie to a single owner or destination

    Security Check:

    Always derive PDAs with seeds that include a user-specific or context-specific component. For example, include the user’s wallet address or the intended destination account as part of the seed so that each PDA is unique to that user’s data. Additionally, use on-chain checks (or Anchor’s : #[account(seeds = ...)]constraints) to verify the PDA is derived from the expected seeds and bump. In our example, the fix was to derive the PDA using the specific withdraw destination as a seed, ensuring only the rightful owner’s PDA could authorize a withdrawal

  3. Royalty handling

    NFT royalties are fees paid to creators on secondary sales, as specified in the token’s metadata (usually by a list of creators and share percentages). On Solana, honoring royalties largely depends on marketplace logic rather than an enforced chain rule. Security (and fairness) checks revolve around ensuring these royalties are correctly calculated and cannot be bypassed or misdirected when using on-chain programs.

    Collection Verification: Importance of the verified Flag : (verified is true : can only be true if the authority on the collection NFT has run the verifyCollection over the NFT)

    Example – Fake NFTs Bypassing Verification: In January 2023, Magic Eden suffered an exploit where unverified NFTs were erroneously displayed as part of verified collections. A bug in their activity indexer allowed fake NFTs to “skirt verification” checks and list alongside genuine ones . This meant users saw what appeared to be legitimate high-value NFTs (like those from the y00ts or ABC collections) for sale, but in reality they were impostors that did not have the proper verified flag. At least 25 fake NFTs across 4 collections were sold to unsuspecting buyers before the issue was caught. The incident underscores the importance of checking that collection_verified is true and that the collection authority is correct whenever an NFT is treated as a member of a collection.

    Beyond marketplace listing, this check is vital for any app granting privileges based on NFT ownership. An app should verify the NFT’s mint address against a known list or verify that its collection field is correctly signed by the project’s authority.

    Security Check: Always enforce collection verification. For developers, use the Metaplex Token Metadata program’s instruction to verify collection items on mint, and for marketplaces or services, reject or flag items that aren’t properly verified. This prevents counterfeit NFTs from sneaking into official channels, a form of tampering that can defraud users and damage trust.

  4. Role/Power Exploits: Risks with NFT-Based Privileges

    NFTs are sometimes used as access tokens or to confer special roles (e.g. an NFT that grants governance voting power, moderator rights, or game abilities). While this is a powerful feature, it introduces role-based security concerns. The contract or application must strictly enforce that only the holders of the NFT can exercise those privileges, and that those privileges update or revoke when the NFT changes hands.

  5. Other Logic Flaws and Tampering to Watch For

    In addition to the categories above, developers should guard against general smart contract bugs that have appeared in the NFT context. For example, initialization flaws can be fatal: the Candy Machine v1 contract had a bug where an attacker could re-initialize the treasury account of the contract and set themselves as the authority, then drain funds. This was essentially a missing check that an account was not already initialized. This reinforces that all state changes (like initializing, setting authorities, etc.) should have proper checks (e.g. “if already initialized, abort”). Likewise, any function that writes to an account should ensure the account is the expected one and not an arbitrary account provided by an attacker.

    Another thing to monitor is metadata content tampering (discussed more later). While not a direct on-chain exploit, if your program uses data from an NFT’s metadata (like a URI or attributes), be cautious. For instance, relying on an NFT’s metadata URL to grant an ability (say any NFT with the trait “Dragon” gets a bonus) could be fooled if someone changes the metadata or if the metadata is not immutable. Always prefer on-chain or verifiable data for critical logic, or at least double-check the source (e.g. the update authority of the metadata is the official one).

    Question to ask yourself if you are auditing and NFT (EVM Examples still true on Solana) :

In summary, the essential security checks for Solana NFT programs include: verifying trade state accounts and ownership, using PDAs with unique seeds and proper signer checks, enforcing royalty rules or at least not allowing easy bypass if promised, checking collection authenticity via the verified flag, and rigorously enforcing that only legitimate NFT holders or authorized persons can invoke restricted actions. Many past vulnerabilities — from Auction House’s logic flaw to Candy Machine’s init bug — stem from missing one of these checks. Learning from those, Solana developers should adopt a defensive mindset and use the established standards (Metaplex’s libraries, Anchor’s constraints, etc.) to avoid repeating mistakes.

0
Subscribe to my newsletter

Read articles from Lilian Cariou directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Lilian Cariou
Lilian Cariou