Platform: Code4rena
Start Date: 09/02/2024
Pot Size: $60,500 USDC
Total HM: 17
Participants: 283
Period: 12 days
Judge:
Id: 328
League: ETH
Rank: 224/283
Findings: 3
Award: $1.35
π Selected for report: 0
π Solo Findings: 0
π Selected for report: Aamir
Also found by: 0rpse, 0x11singh99, 0x13, 0xAlix2, 0xAsen, 0xBinChook, 0xCiphky, 0xE1, 0xKowalski, 0xLogos, 0xWallSecurity, 0xaghas, 0xbranded, 0xlemon, 0xlyov, 0xpoor4ever, 0xprinc, 0xvj, ADM, Aymen0909, BARW, Bauchibred, Breeje, CodeWasp, DMoore, DeFiHackLabs, Draiakoo, Fulum, GhK3Ndf, Greed, Jorgect, Josh4324, Kalogerone, KmanOfficial, Krace, Limbooo, McToady, MidgarAudits, MrPotatoMagic, PedroZurdo, Pelz, Ryonen, SovaSlava, SpicyMeatball, Tendency, Timenov, ZanyBonzy, _eperezok, al88nsk, alexxander, alexzoid, aslanbek, blutorque, btk, cartlex_, cats, csanuragjain, deadrxsezzz, denzi_, devblixt, dimulski, djxploit, erosjohn, evmboi32, fnanni, grearlake, haxatron, hulkvision, immeas, israeladelaja, jaydhales, jesjupyter, jnforja, josephdara, juancito, kiqo, klau5, korok, krikolkk, ktg, kutugu, ladboy233, lil_eth, m4ttm, matejdb, merlinboii, n0kto, ni8mare, novamanbg, nuthan2x, oualidpro, pa6kuda, peter, petro_1912, pkqs90, pynschon, sandy, sashik_eth, shaflow2, shaka, sobieski, soliditywala, solmaxis69, stackachu, tallo, thank_you, tpiliposian, ubl4nk, visualbits, vnavascues, web3pwn, xchen1130, zhaojohnson
0.0037 USDC - $0.00
The GameItems contract implements transferability checks to ERC1155's safeTransferFrom method but misses applying these checks to ERC1155's safeBatchTransferFrom method. This allows non-transferable tokens to be transferred in batch operations, bypassing the intended access control.
The safeTransferFrom implementation can be viewed here: https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L289-L303 The safeTransferFrom method has added checks in place to prevent users transferring tokens that are defined to be non transferable.
However ERC1155 has another transfer method, safeBatchTransferFrom: https://ethereum.org/en/developers/docs/standards/tokens/erc-1155#batch_transfers
A test can be added to GameItems.t.sol to confirm this issue:
function testNonTransferableSafeBatchTransferFrom() public { // Fund the owner with necessary assets (if required) _fundUserWith4kNeuronByTreasury(_ownerAddress); // Battery item, from script/Deployer.s.sol _gameItemsContract.createGameItem( "battery", "https://ipfs.io/ipfs/bafybeibhi6d5l2oqv63gczy6qwprzsspn5t6d5uuvadpl2afzvgtv44h7u", false, false, // transferable = false 0, 10 * 10 ** 18, 5 ); _gameItemsContract.mint(1, 3); // Prepare IDs and amounts for safeBatchTransferFrom uint256[] memory ids = new uint256[](1); ids[0] = 1; // id 0 is taken by a transferable gameItem defined in setUp uint256[] memory amounts = new uint256[](1); amounts[0] = 3; bool passed = false; try _gameItemsContract.safeBatchTransferFrom(_ownerAddress, _DELEGATED_ADDRESS, ids, amounts, "") { passed = false; // Transfer succeeded } catch { passed = true; // Transfer failed (as expected) } assertEq(passed, true); }
This test creates a new gameItem called battery, the test mints some batteries, with the transferable attribute set to false, and then attempts to transfer them using safeBatchTransferFrom. The transfer succeeds, failing the test.
Manual review of the code. Foundry and the projects test suite.
To address the inconsistency in transferability checks, consider implementing the following:
Modify the ERC1155 safeBatchTransferFrom method to loop over the tokenIds and check each token is transferable.
function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) public override(ERC1155) { for (uint256 i = 0; i < ids.length; ++i) { require(allGameItemAttributes[ids[i]].transferable); } super.safeBatchTransferFrom(from, to, ids, amounts, data); }
Enhance the testing suite by adding additional tests, similar to the demonstrated proof of concept, to check that game items flagged as non-transferable adhere to their defined transfer restrictions.
Access Control
#0 - c4-pre-sort
2024-02-22T03:36:12Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T03:36:20Z
raymondfam marked the issue as duplicate of #18
#2 - c4-pre-sort
2024-02-26T00:27:26Z
raymondfam marked the issue as duplicate of #575
#3 - c4-judge
2024-03-05T04:47:39Z
HickupHH3 changed the severity to 3 (High Risk)
#4 - c4-judge
2024-03-05T04:51:24Z
HickupHH3 marked the issue as satisfactory
π Selected for report: klau5
Also found by: 0xAleko, 0xAlix2, 0xAsen, 0xCiphky, 0xKowalski, 0xlemon, 0xvj, 14si2o_Flint, Aamir, AlexCzm, Aymen0909, BARW, Blank_Space, DanielArmstrong, Davide, Draiakoo, Giorgio, McToady, MrPotatoMagic, PoeAudits, Ryonen, Silvermist, SpicyMeatball, Tychai0s, VAD37, Varun_05, alexxander, alexzoid, aslanbek, blutorque, btk, cats, d3e4, denzi_, evmboi32, fnanni, givn, grearlake, haxatron, jesjupyter, juancito, ke1caM, ktg, lanrebayode77, linmiaomiao, matejdb, merlinboii, n0kto, novamanbg, nuthan2x, petro_1912, pynschon, radin100, sashik_eth, shaka, sl1, soliditywala, solmaxis69, t0x1c, ubl4nk, vnavascues, xchen1130, yotov721, zhaojohnson
1.1225 USDC - $1.12
Allowing users to select the fighter type ensures they receive a fighter with predetermined physical attributes. Setting the fighter type to 1 during a reroll guarantees a fighter whose physical attributes are all ones.
Finding can be verified by using ethers with a local deployment of the contracts, the deploy script requires some modification to ensure deployer address has a fighter minted to them and neuron tokens. The inital fighter was created with a fighterType of 0, however when we call reRoll, we pass a fighterType of 1.
const { ethers } = require("ethers"); const fs = require("fs"); const provider = new ethers.JsonRpcProvider("http://127.0.0.1:8545"); const fighterFarmABI = JSON.parse( fs.readFileSync("./out/FighterFarm.sol/FighterFarm.json") ).abi; const fighterFarmAddress = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"; const fighterFarmContract = new ethers.Contract( fighterFarmAddress, fighterFarmABI, provider ); const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider); const fighterFarmWithSigner = fighterFarmContract.connect(signer); const run = async () => { const fighterId = 0; const newFighterType = 1; const fighter = await fighterFarmWithSigner.fighters(fighterId); console.log("Fighter: ", fighter); await fighterFarmWithSigner.reRoll(fighterId, newFighterType); const rerolledFighter = await fighterFarmWithSigner.fighters(fighterId); console.log("Rerolled Fighter: ", rerolledFighter); }; run();
Running this PoC returns:
Fighter: Result(9) [ 80n, 1n, Result(6) [ 4n, 6n, 6n, 10n, 8n, 4n ], 0n, '_neuralNetHash', 'original', 0n, 0n, false ] Rerolled Fighter: Result(9) [ 86n, 2n, Result(6) [ 1n, 1n, 1n, 1n, 1n, 1n ], 0n, '_neuralNetHash', 'original', 0n, 0n, false ]
Executing this script demonstrates that rerolling with a fighter type of 1 modifies the fighter's physical attributes to ones.
Manual Review Ethers, anvil
The fighterType's implementation may lead to confusion as it's not stored with the fighter but influences the dendroidBool, which also has binary states. It's suggested to integrate fighterType more coherently into the fighter's creation or reroll process, allowing the reroll method to directly use fighterType from the fighter's attributes, rather then relying on user input.
Invalid Validation
#0 - c4-pre-sort
2024-02-22T01:22:44Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T01:22:50Z
raymondfam marked the issue as duplicate of #306
#2 - c4-judge
2024-03-05T04:31:57Z
HickupHH3 marked the issue as satisfactory
#3 - c4-judge
2024-03-19T09:05:07Z
HickupHH3 changed the severity to 3 (High Risk)
π Selected for report: ahmedaghadi
Also found by: 0x13, 0xAleko, 0xDetermination, 0xKowalski, 0xPluto, 0xRiO, 0xvj, AlexCzm, Avci, BARW, BigVeezus, Cryptor, DeFiHackLabs, Draiakoo, Fitro, Giorgio, GoSlang, Greed, Honour, Kalogerone, KmanOfficial, Krace, McToady, MidgarAudits, MrPotatoMagic, Nyxaris, ReadyPlayer2, Ryonen, SovaSlava, SpicyMeatball, VAD37, _eperezok, alexzoid, almurhasan, btk, cu5t0mpeo, deadrxsezzz, djxploit, dvrkzy, emrekocak, erosjohn, evmboi32, fnanni, grearlake, inzinko, jesjupyter, jesusrod15, josephdara, ke1caM, klau5, ktg, ladboy233, merlinboii, nuthan2x, peanuts, pipidu83, pontifex, radev_sw, sl1, sobieski, soliditywala, t0x1c, taner2344, vnavascues, y4y, yovchev_yoan, zaevlad
0.2347 USDC - $0.23
Judge has assessed an item in Issue #1028 as 2 risk. The relevant finding follows:
[L-1] Potential DoS from High roundId/winnerAddresses in MergingPool::claimRewards
#0 - c4-judge
2024-03-12T02:58:09Z
HickupHH3 marked the issue as duplicate of #216
#1 - c4-judge
2024-03-12T02:58:14Z
HickupHH3 marked the issue as partial-25
#2 - c4-judge
2024-03-21T03:03:16Z
HickupHH3 marked the issue as satisfactory