Platform: Code4rena
Start Date: 22/09/2023
Pot Size: $100,000 USDC
Total HM: 15
Participants: 175
Period: 14 days
Judge: alcueca
Total Solo HM: 4
Id: 287
League: ETH
Rank: 89/175
Findings: 2
Award: $25.79
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xTheC0der
Also found by: 0x180db, 0xDING99YA, 0xRstStn, 0xTiwa, 0xWaitress, 0xblackskull, 0xfuje, 3docSec, Aamir, Black_Box_DD, HChang26, Hama, Inspecktor, John_Femi, Jorgect, Kek, KingNFT, Kow, Limbooo, MIQUINHO, MrPotatoMagic, NoTechBG, Noro, Pessimistic, QiuhaoLi, SovaSlava, SpicyMeatball, T1MOH, TangYuanShen, Vagner, Viktor_Cortess, Yanchuan, _eperezok, alexweb3, alexxander, ast3ros, ayden, bin2chen, blutorque, btk, ciphermarco, ether_sky, gumgumzum, gztttt, hals, imare, its_basu, joaovwfreire, josephdara, klau5, kodyvim, ladboy233, marqymarq10, mert_eren, minhtrng, n1punp, nobody2018, oada, orion, peakbolt, peritoflores, perseverancesuccess, pfapostol, rvierdiiev, stuxy, tank, unsafesol, ustas, windhustler, zambody, zzzitron
0.1127 USDC - $0.11
A VirtualAccount
represents a user wallet that allows the user to manage assets and perform remote interactions.
But because payableCall
method lacks any form of authentication it can be called by anyone.
The call can be also executed directly to the desired VirtualAccount
instance (as shown by the POC in this report).
Anyone can call (directly) any VirtualAccount
user contract and execute asset movements or any desired interaction in the name of the user (wallet).
This line is missing an access modifier:
Add the following test to the MulticallRootRouterTest.t.sol
file :
// add this after helper import import {PayableCall} from "@omni/interfaces/IVirtualAccount.sol"; // add as one of the tests function testAnyoneCanInteractWithTheUserVirtualAccount() public { // userVirtualAccount variable is defined as : //userVirtualAccount = address(rootPort.fetchVirtualAccount(address(this))); PayableCall[] memory payableCallData = new PayableCall[](1); payableCallData[0] = PayableCall({target: mockApp, callData: abi.encodeWithSelector(bytes4(keccak256(bytes("distro()")))), value : 0}); // RLP Encode Calldata bytes memory data = encodeCalls(abi.encode(payableCallData)); hevm.startPrank(address(0x1337)); // value can be anything ..also 0 userVirtualAccount.call{value : 0}(abi.encodeWithSignature("payableCall(PayableCall[] data)", data)); hevm.stopPrank(); }
The test will succeed to run and will show that anyone can directly call an VirtualAccount
that makes interactions on behalf of the user.
Running 1 test for test/ulysses-omnichain/MulticallRootRouterTest.t.sol:MulticallRootRouterTest [PASS] testAnyoneCanInteractWithTheUserVirtualAccount() (gas: 13697) Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.68ms Running 1 test for test/ulysses-omnichain/MulticallRootRouterZippedTest.t.sol:MulticallRootRouterZipTest [PASS] testAnyoneCanInteractWithTheUserVirtualAccount() (gas: 47730) Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.84ms
Manual review
Add an access modifier like is done for VirtualAccount#call
method
-function payableCall(PayableCall[] calldata calls) public payable returns (bytes[] memory returnData) { +function payableCall(PayableCall[] calldata calls) public payable returns (bytes[] memory returnData) requiresApprovedCaller {
Access Control
#0 - c4-pre-sort
2023-10-08T14:03:24Z
0xA5DF marked the issue as duplicate of #888
#1 - c4-pre-sort
2023-10-08T14:37:02Z
0xA5DF marked the issue as sufficient quality report
#2 - c4-judge
2023-10-26T11:29:03Z
alcueca marked the issue as satisfactory
#3 - c4-judge
2023-10-26T11:32:08Z
alcueca changed the severity to 3 (High Risk)
🌟 Selected for report: MrPotatoMagic
Also found by: 0xAadi, 0xDING99YA, 0xDemon, 0xRstStn, 0xSmartContract, 0xStriker, 0xWaitress, 0xbrett8571, 0xfuje, 0xsagetony, 0xsurena, 33BYTEZZZ, 3docSec, 7ashraf, ABA, ABAIKUNANBAEV, Aamir, Audinarey, Bauchibred, Black_Box_DD, Daniel526, DanielArmstrong, DanielTan_MetaTrust, Dinesh11G, Eurovickk, Franklin, Inspecktor, John, Jorgect, Joshuajee, K42, Kek, Koolex, LokiThe5th, MIQUINHO, Myd, NoTechBG, QiuhaoLi, SanketKogekar, Sathish9098, Sentry, Soul22, SovaSlava, Stormreckson, Tendency, Topmark, Udsen, V1235816, Viktor_Cortess, Viraz, Yanchuan, ZdravkoHr, Zims, albahaca, albertwh1te, alexweb3, alexxander, ast3ros, audityourcontracts, bareli, bin2chen, bronze_pickaxe, c0pp3rscr3w3r, cartlex_, castle_chain, chaduke, debo, ether_sky, gumgumzum, imare, its_basu, jaraxxus, jasonxiale, josephdara, kodyvim, ladboy233, lanrebayode77, lsaudit, mert_eren, minhtrng, n1punp, nadin, niroh, nmirchev8, orion, peakbolt, perseverancesuccess, pfapostol, ptsanev, rvierdiiev, saneryee, shaflow2, te_aut, terrancrypt, twcctop, unsafesol, ustas, versiyonbir, windhustler, yongskiws, zhaojie, ziyou-
25.6785 USDC - $25.68
https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/BranchBridgeAgent.sol#L142 https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/BranchBridgeAgent.sol#L943 https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/RootBridgeAgent.sol#L1210
Layer0 supports also chains that have different address byte size then 20.
https://layerzero.gitbook.io/docs/technical-reference/mainnet/supported-chain-ids
A chain that support size different address then 20 is for example Aptos chain.
Such chain can be added to the protocol but will not work as expected.
Such chain can be added as its shown by this lines:
This line will not revert:
rootBridgeAgentPath = abi.encodePacked(_rootBridgeAgentAddress, address(this));
But inside the executor contract (the BranchBridgeAgentExecutor
) the modifier that protects the receive functionality expects a different size of address
if (_srcAddress.length != 40) revert LayerZeroUnauthorizedCaller(); if (rootBridgeAgentAddress != address(uint160(bytes20(_srcAddress[20:])))) revert LayerZeroUnauthorizedCaller();
There is also a line in the RootBridgeAgent
contract:
Manual review
To achieve compatibility for such type of chain there is a lot of code to change. For example we should not use address type but bytes instead.
The simplest solution would be to not support such chain.
Error
#0 - c4-pre-sort
2023-10-07T14:03:42Z
0xA5DF marked the issue as primary issue
#1 - 0xA5DF
2023-10-07T14:04:00Z
Leaving open for sponsor to comment whether they intend to use chains like Aptos
#2 - c4-pre-sort
2023-10-07T14:04:03Z
0xA5DF marked the issue as sufficient quality report
#3 - c4-sponsor
2023-10-17T19:55:54Z
0xBugsy (sponsor) disputed
#4 - alcueca
2023-10-26T08:53:22Z
On what grounds is this being disputed?
#5 - 0xBugsy
2023-10-26T14:41:55Z
This is intended, we are only implementing EVM compatible chains trying to add different chains will not be allowed by our governance process and this interactions would revert in the setup process of the new chain. Furthermore, we don't have any Branch contracts developed that could be deployed in said chains so any impact through this isn't really feasible.
#6 - alcueca
2023-10-27T08:56:55Z
Valid QA to add in the documentation as project scope.
#7 - c4-judge
2023-10-27T08:57:04Z
alcueca changed the severity to QA (Quality Assurance)
#8 - c4-judge
2023-10-27T08:57:10Z
alcueca marked the issue as grade-b