Canto Identity Subprotocols contest - mjmoonwalker's results

Subprotocols for Canto Identity Protocol.

General Information

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

Canto Identity Subprotocols

Findings Distribution

Researcher Performance

Rank: 79/98

Findings: 1

Award: $19.87

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Awards

19.8705 USDC - $19.87

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
edited-by-warden
duplicate-212

External Links

Lines of code

https://github.com/code-423n4/2023-03-canto-identity/blob/077372297fc419ea7688ab62cc3fd4e8f4e24e66/canto-bio-protocol/src/Bio.sol#L121

Vulnerability details

Impact

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.

Proof of Concept

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; } }

Tools Used

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter