Canto Identity Subprotocols contest - dec3ntraliz3d'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: 12/98

Findings: 1

Award: $401.03

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: volodya

Also found by: Emmanuel, IgorZuk, Rappie, adriro, dec3ntraliz3d, descharre, igingu, m9800

Labels

bug
3 (High Risk)
satisfactory
duplicate-117

Awards

401.0269 USDC - $401.03

External Links

Lines of code

https://github.com/code-423n4/2023-03-canto-identity/blob/077372297fc419ea7688ab62cc3fd4e8f4e24e66/canto-namespace-protocol/src/Namespace.sol#L144

Vulnerability details

Impact

The fuse() function in Namespace.sol incorrectly calculates fused bytes. The first parameter to the characterToUnicodeBytes() function is font class, which is always set to 0. This leads to an incorrect calculation of the tokenToName value, resulting in a bunch of emojis instead of the expected characters. For example, a list of tiles with characters b, 9, 😪, 𝓇, 8, 😮, 𝔢 will become ✅🤔😪😂🎂😮☕ instead of b9😪𝓇8😮𝔢.

This is a high severity issue as it can create incorrect associations in the nameToToken and tokenToName mappings, leading to various issues. The main goal of Namespace contract is to able to fuse tiles and generate name from the tile's character. fuse() function fails due to this bug.

bytes memory charAsBytes = Utils.characterToUnicodeBytes(0, tileData.characterIndex, characterModifier);

Proof of Concept

This issue can easily be verified using the below foundry test. First, create a tray with tokenId 1 as an owner. Then, fuse all the tiles in that tray. The expected output name is b9😪𝓇8😮𝔢, but due to this bug, the output is a bunch of emojis ✅🤔😪😂🎂😮☕ . Basically any character that is not an emoji is lost.

function testPoc() public { vm.startPrank(owner); tray.buy(1); assertEq(tray.balanceOf(owner), 1); note.approve(address(ns), type(uint256).max); ns.fuse(buildCharacters(1)); // first Tray generates tiles with b, 9, 😪, 𝓇, 8, 😮, 𝔢 // after fusing it the name should be b9😪𝓇8😮𝔢 string memory expectedName = unicode"b9😪𝓇8😮𝔢"; // assertion fails assertEq(ns.tokenToName(1), expectedName); vm.stopPrank(); }
.... .... .... ├─ [1088] Namespace::tokenToName(1) [staticcall] │ └─ ← ✅🤔😪😂🎂😮☕ ├─ emit log(: Error: a == b not satisfied [string]) ├─ emit log_named_string(key: Value a, val: ✅🤔😪😂🎂😮☕) ├─ emit log_named_string(key: Value b, val: b9😪𝓇8😮𝔢) ├─ [0] VM::stopPrank() │ └─ ← () └─ ← () Test result: FAILED. 0 passed; 1 failed; finished in 8.26ms Failing tests: Encountered 1 failing test in src/test/Namespace.t.sol:NamespaceTest [FAIL. Reason: Assertion failed.] testPoc() (gas: 593578)

Tools Used

Manual.

The fix is very simple. When converting a character to Unicode bytes, make sure to pass the font class of the tile as shown below:

- bytes memory charAsBytes = Utils.characterToUnicodeBytes(0, tileData.characterIndex, characterModifier); + bytes memory charAsBytes = Utils.characterToUnicodeBytes(tileData.fontClass, tileData.characterIndex, characterModifier);

#0 - c4-judge

2023-03-28T22:01:35Z

0xleastwood marked the issue as duplicate of #117

#1 - c4-judge

2023-04-11T19:29:02Z

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