Back

Blog details

Content Addressing for NFTs: How to Verify a CID Yourself

AIOZ Network
5 min readAugust 15, 2026
aioz-pinnftexplainer
Holographic hexagon tiles representing AIOZ Pin's IPFS storage network

Other articles on this blog have said that a CID makes NFT metadata tamper-evident. This one shows you how to verify a CID yourself instead of taking that claim on faith, by recomputing it from a file and comparing it to what's on-chain. If they match, nothing changed. If they don't, something did.

TL;DR:
  • A CID is computed by hashing a file's content (SHA2-256 by default) and combining it with codec metadata, not assigned by a server
  • Any change to the file, even one byte, produces a completely different CID
  • You can independently verify this with ipfs add --only-hash <file>, which computes a CID locally without uploading anything
  • If the recomputed CID matches what's referenced on-chain, the file is provably unaltered

What's Actually Inside a CID

A CIDv1 is built from four parts: a multibase prefix indicating the encoding (b for base32, the default), a version identifier, a multicodec identifying how the data is structured, and a multihash, which itself contains the hash algorithm used (SHA2-256 by default) and the resulting digest. None of this is assigned by whoever's hosting the file. It's derived entirely from the file's own bytes. Two identical files uploaded from two different computers by two different people produce the exact same CID, and per IPFS's own documentation, "any difference in the content will produce a different CID."

That's the whole mechanism behind CID-based tamper detection: there's no separate "integrity check" bolted on, the address and the fingerprint are the same thing.

Verifying a Whole Directory, Not Just a Single File

NFT metadata sometimes references more than one file, an image plus a separate metadata JSON, or a folder of assets for a generative collection. ipfs add --only-hash works recursively too: pointed at a directory rather than a single file, it computes a CID for the whole folder structure the same way it would for one file, without uploading anything. This matters because a directory's CID depends on every file inside it, covered in more depth in how IPFS represents files and directories, so verifying a collection's root CID in one pass confirms every file inside it is unaltered, not just the top-level structure. It's the same verification principle scaled up: one recomputed hash, one comparison, covering an entire collection instead of a single asset.

Computing a CID Without Uploading Anything

The Kubo CLI (IPFS's reference implementation) has a flag built for exactly this: --only-hash.

ipfs add --only-hash --cid-version 1 my-nft-metadata.json

This computes what the CID would be if you pinned the file, without actually adding it to your local node or uploading it anywhere. It's a pure, local hash computation, useful specifically for verification: you're not trying to store the file, you're trying to confirm what its CID should be.

Verifying an NFT's Metadata Hasn't Changed

Put those two things together and you get a real, repeatable verification workflow:

  1. Download the file currently being served at the NFT's ipfs://{cid} reference (through any gateway)
  2. Run ipfs add --only-hash --cid-version 1 on the downloaded file
  3. Compare the output to the CID in the ipfs:// URI the NFT contract actually references

If they match, you've confirmed the content being served today is byte-for-byte the same as whatever was originally pinned under that CID, not just "probably fine" but cryptographically verified. If they don't match, either the gateway served you something different than the actual pinned content (worth investigating on its own), or the CID reference itself was never actually the file people assumed it was.

A Common Pitfall: CID Version Mismatches

Recomputing a CID and getting a different result doesn't automatically mean the content changed, it's worth ruling out a simpler explanation first: CID version mismatch. An NFT minted a while back may reference a CIDv0 identifier (the 46-character string starting with Qm), while ipfs add --only-hash without an explicit flag defaults to CIDv1 on current versions of the Kubo CLI, producing a completely different-looking string (starting with b) for the exact same underlying content. This isn't a tampering signal, it's the same file represented two different ways. Always pass --cid-version 0 explicitly if the on-chain reference is a Qm... CIDv0 string, or convert one representation to the other before comparing, rather than concluding the content changed just because the string format doesn't match. The CID anatomy breakdown covers exactly what differs between the two versions if the distinction isn't already familiar.

Why This Matters More for NFTs Than Most Files

A regular file you download once and move on. An NFT's metadata is a claim that persists as long as the token exists, someone minted it, someone else may buy it later based on what that metadata says, and there's no built-in mechanism forcing anyone to re-check it after the fact. Being able to independently verify a CID, rather than trusting whatever a marketplace's cached preview shows you, is the actual practical value of content addressing for this specific use case. It's not just a technical curiosity, it's the difference between "the metadata probably hasn't changed" and "I checked."

Frequently Asked Questions

What determines an NFT's CID? The content of the file itself, hashed with SHA2-256 by default and combined with codec metadata. It's not assigned by a server or chosen by whoever uploads it.

Can I verify a CID without re-uploading the file? Yes, with ipfs add --only-hash <file> using the Kubo CLI. It computes the CID locally without adding the file to your node or the network.

What does it mean if my recomputed CID doesn't match the on-chain reference? Either the content you downloaded differs from what was originally pinned under that CID, or the reference itself doesn't point at what you expected. Either way, it's worth investigating before trusting the metadata.

Does changing even a small part of a file change its CID? Yes. Per IPFS's own documentation, any difference in content produces a different CID, there's no threshold, even a single byte change is enough.

Why does content addressing matter more for NFTs than regular file storage? NFT metadata is a persistent claim tied to a token that may be resold based on what it says. Independently verifying the CID confirms the metadata is exactly what was originally set, rather than trusting a marketplace's cached display.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

How IPFS Splits Files: Fixed vs. Content-Defined Chunking

IPFS defaults to 256 KiB fixed-size chunks, but also ships Rabin and Buzhash content-defined chunkers. Here is why the choice affects deduplication.

5 min readAugust 23, 2026
blog thumbnail

Anatomy of a CID: Decoding an IPFS Identifier

An IPFS CID is not a random string. It encodes a version, a codec, and a hash algorithm plus digest. Here is how to decode a real CID piece by piece.

5 min readAugust 22, 2026
blog thumbnail

How IPFS Shards Large Directories: The HAMT, Not a B-Tree

IPFS does not use a B-tree for large directories. It uses a HAMT, a Hash Array Mapped Trie. Here is exactly how it shards a folder once it outgrows one block.

5 min readAugust 21, 2026
blog thumbnail

How to Resize Images on AIOZ Pin Using URL Parameters

AIOZ Pin image resizing happens straight in the gateway URL, no upload step or separate service. Here is every img- parameter, with real srcset examples.

5 min readAugust 19, 2026
blog thumbnail

How x402 Payments Weight AI Agent Reputation on ERC-8004

x402 payments let ERC-8004 weight a paid AI agent interaction more heavily than free work in its reputation score. Here is exactly how that link works.

5 min readAugust 18, 2026
blog thumbnail

How to Automate NFT Pinning with the AIOZ Pin NFT API

AIOZ Pin NFT API calls pin an asset and its metadata as two tracked pins under one record. Here is how to automate it directly over REST, no SDK needed.

5 min readAugust 17, 2026