Skip to content

Mutable On-Chain Metadata

id: LS29M
title: Mutable On-Chain Metadata
baseSeverity: M
category: metadata
language: solidity
blockchain: [ethereum, polygon, arbitrum, optimism, bsc]
impact: Trust erosion, rugpull risk, and incorrect display of NFTs
status: draft
complexity: low
attack_vector: internal
mitigation_difficulty: easy
versions: [">=0.5.0", "<=0.8.25"]
cwe: CWE-494: Download of Code Without Integrity Check
swc: SWC-138: Unencrypted Sensitive Data on Chain

๐Ÿ“ Description

  • Mutable On-Chain Metadata occurs when an NFT or token contract allows the modification of metadata URIs or token descriptors after mint, typically through functions like setBaseURI, setTokenURI, or full rewrites to token metadata mappings.
  • This introduces serious trust and security risks:
  • Creators or admins can swap images, traits, or even remove metadata
  • Marketplaces display incorrect or misleading asset visuals
  • Tokens become untrustworthy over time (e.g., "rugpull" NFTs)
  • This design violates the immutability principle of NFTs and undermines interoperability across dApps, games, and marketplaces.

๐Ÿšจ Vulnerable Code

string private baseURI;

function setBaseURI(string calldata _uri) external onlyOwner {
    baseURI = _uri; // โŒ mutable metadata source
}

๐Ÿงช Exploit Scenario

Step-by-step exploit process:

  1. An NFT project mints thousands of tokens with attractive art.
  2. baseURI is mutable and stored on a centralized or editable server (e.g., IPFS with modifiable gateway or HTTP server).
  3. After users purchase the NFTs, the project owner calls setBaseURI(), updating metadata to:

Assumptions:

  • The contract owner or admin retains control over metadata pointers (e.g., baseURI, tokenURI).
  • There is no immutable, finalized, or locked flag post-mint.
  • NFT data (art, traits, metadata.json) is hosted off-chain or through a mutable pointer.

โœ… Fixed Code

string private baseURI;
bool public metadataFrozen;

function setBaseURI(string calldata _uri) external onlyOwner {
    require(!metadataFrozen, "Metadata is frozen");
    baseURI = _uri;
}

function freezeMetadata() external onlyOwner {
    metadataFrozen = true;
}

๐Ÿงญ Contextual Severity

- context: "Default"
  severity: M
  reasoning: "Trust is affected, but no direct asset loss."
- context: "NFT project with post-sale metadata updates"
  severity: H
  reasoning: "Metadata tampering leads to reputational damage and user loss."
- context: "Verified immutable metadata with freeze option"
  severity: L
  reasoning: "Only legacy misuse cases remain due to freezing mechanism."

๐Ÿ›ก๏ธ Prevention

Primary Defenses

  • Use freezeMetadata() or permanent URIs after mint.
  • Prefer fully on-chain metadata or IPFS CID pinned content.
  • Emit MetadataFrozen() event for marketplace and user verification.

Additional Safeguards

  • Store hash of metadata on-chain to verify integrity.
  • Implement permissionless access to freeze metadata after a deadline.
  • Use decentralized pinning services or Arweave for immutability.

Detection Methods

  • Static scan for setBaseURI, setTokenURI, or modifiable metadata variables.
  • Check deployer privileges and access control around URI modification.
  • Tools: Slither (unprotected-write), OpenSea's metadata freeze scanner

๐Ÿ•ฐ๏ธ Historical Exploits

  • Name: Pixelmon NFT Reveal Controversy
  • Date: 2022-02
  • Loss: ~$70,000,000 (raised)
  • Post-mortem: Link to post-mortem

๐Ÿ“š Further Reading


โœ… Vulnerability Report

id: LS29M
title: Mutable On-Chain Metadata
severity: M
score:
impact: 3  
exploitability: 3  
reachability: 4  
complexity: 2  
detectability: 3  
finalScore: 3.1

๐Ÿ“„ Justifications & Analysis

  • Impact: Can irreversibly destroy NFT value and damage marketplace trust.
  • Exploitability: Easily triggered by contract owner without user consent.
  • Reachability: Common in early NFT contracts and poorly-audited mints.
  • Complexity: Very low โ€“ calling a setter function.
  • Detectability: Detectable via Slither and audit of URI-related logic.