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

Findings: 2

Award: $423.80

🌟 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/main/canto-namespace-protocol/src/Namespace.sol#L144

Vulnerability details

Impact

When registering a name containing a non-emoji tile, all the tiles are mapped to emoji tiles before registering a name, so the registered name is invalid. This ruins the protocol, the users can't use it to register the desired names unless they are purely emoji-based.

Proof of Concept

Add and run a test to canto-namespace-protocol/src/test/Namespace.t.sol:

// An extra import
import {Tray, Utils} from "../Tray.sol";
// The test itself
function mintTile(string memory character) internal returns (uint256 trayId, uint8 offset) {
    bytes32 tileHash = keccak256(bytes(character));
    while(true) {
        trayId = tray.nextTokenId();
        tray.buy(1);
        Tray.TileData[7] memory tiles = tray.getTiles(trayId);
        for(offset = 0; offset < tiles.length; offset++) {
            bytes memory tileCharacter = Utils.characterToUnicodeBytes(
                tiles[offset].fontClass,
                tiles[offset].characterIndex,
                tiles[offset].characterModifier);
            if(keccak256(tileCharacter) == tileHash) return (trayId, offset);
        }
    }
}

function testRegistered() public {
    vm.startPrank(owner);
    (uint256 trayId, uint8 offset) = mintTile("a");
    uint256 namespaceId = ns.nextNamespaceIDToMint() + 1;
    Namespace.CharacterData[] memory data = new Namespace.CharacterData[](1);
    data[0] = Namespace.CharacterData(trayId, offset, 0);
    tray.approve(address(ns), trayId);
    ns.fuse(data);
    assertEq(ns.tokenToName(namespaceId), "a", "Invalid name");
}

And run it:

forge test --mt testRegistered -vv

The result is:

[FAIL. Reason: Assertion failed.] testRegistered() (gas: 4667890) Logs: Error: Invalid name Error: a == b not satisfied [string] Value a: ✨ Value b: a

The a, which is the first character of font type 1 got registered after mapping to the first character of font type 0, which is a ✨ emoji.

Tools Used

Foundry

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

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

Or, if that's desired, use fontClass of 1 for all non-zero font classes to remove collisions between differently styled characters.

#0 - c4-judge

2023-03-28T21:59:27Z

0xleastwood marked the issue as duplicate of #117

#1 - c4-judge

2023-04-11T19:28:36Z

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