NFTs are only as secure as their creator makes them. As with any emerging technology, taking shortcuts in the design stages can have disastrous consequences down the line.
Kraken Security Labs scanned thousands of smart contracts on the Ethereum blockchain to take advantage of vulnerabilities left open in certain non-fungible token (NFT) contracts.
Below, the team details how we were able to take over two vulnerable NFTs with little effort and also show how to protect yourself against this kind of insecure NFT.
How an NFT’s media & metadata are stored
Contrary to popular belief, not all NFT media (or metadata) is stored on a blockchain. In many cases — such as in the ERC-721 contracts we’re about to see — the blockchain merely stores a pointer to where the media is kept, like a bank vault that contains a piece of paper with the address of where a piece of art is stored.
Regardless of your bank’s security, that piece of paper isn’t going to be of much use if someone goes to the address and replaces the art.
The blockchain merely stores a link to the media.
Here’s where a malicious actor takes interest. What website or host is holding the media? Who’s paying them to store it? How long is that link going to be alive? And can the on-chain pointer be updated?
Kraken Security Labs scanned thousands of NFTs for expired links (expired websites or custom URLs from hosting services). Surprisingly, this scan turned up a large number of vulnerable tokens.
Taking over NFT metadata hosted on GitHub
The team first identified a token named UniOption, whose contract was created in December 2020. The contract’s TokenURI method revealed that the token’s metadata was hosted at stacksideflow.github.io:
The URL to the token’s metadata.
But upon visiting the page, a 404 error popped up — indicating that the page doesn’t exist.
Typically, the github.io domain hosts user content with a URL in the format of username.github.io. But, we couldn’t find a user named stacksideflow — suggesting that the account had since been renamed or deleted.
From there, we registered a new account with the username and created a repository. With a little more configuration, we made it so we could deliver custom content via the stacksideflow.github.io URL:
Mimicking the path pointed to in the NFT contract, we added a simple JSON file to our new repository that would deliver our metadata to the token:
The name, description and image have been changed.
And just like that, we’ve changed the NFT’s media! The new name, description and image can be seen on NFT explorer sites such as OpenSea and Rarible.
Taking over an expired metadata domain
Next, we looked at ksfootball — a soccer-themed collection of digital art.
The team’s next victim.
On quick review, we found that the content was served by a domain called ksfootball.app:
Again, we queried the tokenURI method to find this information.
A search revealed that the domain was expired, and could be purchased for a few dollars. From there, we bought the domain and, similarly to the previous example, set up a path to deliver custom metadata to the NFTs.
Again, if we look up the collection on Rarible or OpenSea, we can see the changes made to the image, title and description.
The now-updated NFT metadata on Rarible.
How do I know if my NFT metadata is safe?
We targeted inactive tokens for the purposes of this research — but the same techniques could be applied to tokens you may own.
Always remember that, while blockchain data may be immutable, where it points to isn’t always as secure. When a smart contract hardcodes a URL subject to change, that URL could be hijacked.
In addition, some contracts may include functions that allow the contract owner or the token holder to update the URL, in which case it isn’t static and could change in the future. Currently there’s no easy way to detect this ‘updatable URL’ vulnerability, though reviewing the smart contract code (if available) on pages such as Etherscan can protect against this.
For ERC-721 NFTs, Kraken Security Labs advises that you always check where your token’s metadata is stored. You can do this by calling the contract’s tokenURI method, for example by using Etherscan.io. Using the Read Contract feature, you can get the URI of your token’s metadata.
Beyond checking the tokenURI, you should ensure that the image URL in the metadata also points to a trusted location.
Ideally, if your NFT stores its data off-chain, it should be hosted on a system such as Arweave or IPFS (the Interplanetary File System). Careful with IPNS (the Interplanetary Name System) links, as those links are not guaranteed to be immutable. For example, a regular IPFS link (beginning with ipfs://ipfs/… ) cannot be tampered with, has no single point of failure, and content-addressable storage. However, with IPFS, one needs to continuously pin the file on an IPFS node, so it’s not safe from expiry, unlike with systems such as Arweave.