Platform: Code4rena
Start Date: 17/03/2023
Pot Size: $36,500 USDC
Total HM: 10
Participants: 98
Period: 3 days
Judge: leastwood
Total Solo HM: 5
Id: 223
League: ETH
Rank: 79/98
Findings: 1
Award: $19.87
🌟 Selected for report: 0
🚀 Solo Findings: 0
19.8705 USDC - $19.87
The tokenURI function of a given NFT contract must represent truth about the given tokenid.
The Bio contract allows for minting of NFTs using a bio string. The tokenURI of a minted Bio NFT in turn generates a JSON response. This JSON payload includes the bio string in the "description" field. The JSON payload also includes an on-chain SVG image of the bio string.
It is possible for users to mint Bio NFTs in a way that the SVG image string does not match the description field. And so the truthfulness of the tokenURI function is compromised.
User mints a Bio NFT with the following string as the _bio parameter:
string memory _biostring = '","name": "something else","description":"something else entirely","blah":"';
The tokenURI of such a Bio NFT will return the following JSON payload:
{ "name": "Bio #1", "description": "", "name": "something else", "description": "something else entirely", "blah": "", "image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIG1lZXQiIHZpZXdCb3g9IjAgMCA0MDAgMTAwIj48c3R5bGU+dGV4dCB7IGZvbnQtZmFtaWx5OiBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7IH08L3N0eWxlPjx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBkb21pbmFudC1iYXNlbGluZT0ibWlkZGxlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj48dHNwYW4geD0iNTAlIiBkeT0iMjAiPiIsIm5hbWUiOiAic29tZXRoaW5nIGVsc2UiLCJkZXNjcmlwdGlvbiI8L3RzcGFuPjx0c3BhbiB4PSI1MCUiIGR5PSIyMCI+OiJzb21ldGhpbmcgZWxzZSBlbnRpcmVseSIsImJsYWgiOiI8L3RzcGFuPjwvdGV4dD48L3N2Zz4=" }
The decoded SVG image is:
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 400 100"><style>text { font-family: sans-serif; font-size: 12px; }</style><text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle"><tspan x="50%" dy="20">","name": "something else","description"</tspan><tspan x="50%" dy="20">:"something else entirely","blah":"</tspan></text></svg>
When a user views the SVG the following text is displayed:
","name": "something else","description":"something else entirely","blah":"
This is a mismatch from the value of the description field which is set to:
something else entirely
Note that according to https://262.ecma-international.org/13.0/#sec-json-object:
In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.
i.e. consider the super simple parse.tsc (assuming output from tokenURI is stored in ./payload.json):
import payload from './payload.json'; console.log("description:", payload.description);
Will output:
description: something else entirely
while the run time rendering of the SVG displays:
","name": "something else","description":"something else entirely","blah":"
Therefore, the integrity of the tokenURI response is violated.
Forge/foundry test:
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.0 <0.9.0; import "lib/forge-std/src/Test.sol"; import "lib/solmate/src/tokens/ERC721.sol"; import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol"; import {Bio} from "code/2023-03-canto-identity/canto-bio-protocol/src/Bio.sol"; contract CantoIDTest is Test, IERC721Receiver { function setUp() public {} function testBiomismatch() public { Bio mybio = new Bio(); string memory _biostring = '","name": "something else","description":"something else entirely","blah":"'; mybio.mint(_biostring); // mybio.mint("test"); string memory myuri = mybio.tokenURI(1); console2.log(myuri); } receive() external payable { //console2.log("receive"); } fallback() external payable { //console2.log("fallback"); } function onERC721Received( address, address, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
Forge/foundry
In mint(), escape ASCII double quote characters if present in _bio, or disallow them as invalid input.
#0 - c4-judge
2023-03-28T03:55:50Z
0xleastwood marked the issue as duplicate of #212
#1 - c4-judge
2023-03-30T20:27:00Z
0xleastwood changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-04-11T19:32:16Z
0xleastwood marked the issue as satisfactory