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: 158/175
Findings: 1
Award: $0.11
🌟 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
https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/RootBridgeAgent.sol#L175-L199 https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/RootBridgeAgent.sol#L233-L271 https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/VirtualAccount.sol#L85-L112
When a user wants to send funds from Root to Branch they call RootBridgeAgent.callOutAndBridge()
. In the case of where this transferral of funds fails, the user can call RootBridgeAgent.retrySettlement()
. However, an attacker can abuse the VirtualAccount from the victim by calling VirtualAccount.payableCall()
in order to subsequently call RootBridgeAgent.retrySettlement()
to claim the funds for themselves by specifying the _recipient
to be themself. Thus the attacker steals funds from the user.
Note that the VirtualAccount from the victim user is allowed to call RootBridgeAgent.retrySettlement()
because of line 248-250 in RootBridgeAgent:
// RootBridgeAgent.sol 248 if (msg.sender != address(IPort(localPortAddress).getUserAccount(settlementReference.owner))) { 249 revert NotSettlementOwner(); 250 }
The POC below is doing the following:
Funds are first bridged from the AVAX branch to root.
Then subsequently bridged back from root to AVAX branch by MulticallRootRouter using RootBridgeAgent.callOutAndBridge()
, which is failing.
Then the attacker calls VirtualAccount.payableCall()
which calls RootBridgeAgent.retrySettlement()
and specifying themself as recipient.
As a result the attacker gets minted the victim users funds on the branch.
https://gist.github.com/zzzitron/ce2a744c3cbe1e4028d650da683d7f13
Manual review
Consider adding the requiresApprovedCaller
access control modifier to VirtualAccount.payableCall()
so that the attacker can't abuse this function.
Access Control
#0 - c4-pre-sort
2023-10-08T14:06:01Z
0xA5DF marked the issue as duplicate of #888
#1 - c4-pre-sort
2023-10-08T14:38:11Z
0xA5DF marked the issue as sufficient quality report
#2 - c4-judge
2023-10-26T11:29:37Z
alcueca marked the issue as satisfactory