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: 134/175
Findings: 2
Award: $11.58
🌟 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
The Virtual Account holds user balances and users for operating and interacting with Dapps on Arbitrum chain. Since it acts as a Wallet it holds assets. The payableCall()
function acts similar as call()
function, the Issue here it's missing the requiresApprovedCaller
Modifier.
Thus, anyone can call payableCall()
function and execute anything without approved by the User who owns that Virtual Account.
payableCall()
function will following Values:_call.target = USDC Token Address _call.callData = approve(attacker_address, 10000) _call.value = 0
Vulnerable Snippet
function payableCall(PayableCall[] calldata calls) public payable returns (bytes[] memory returnData) { uint256 valAccumulator; uint256 length = calls.length; returnData = new bytes[](length); PayableCall calldata _call; for (uint256 i = 0; i < length;) { _call = calls[i]; uint256 val = _call.value; // Humanity will be a Type V Kardashev Civilization before this overflows - andreas // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256 unchecked { valAccumulator += val; } bool success; if (isContract(_call.target)) (success, returnData[i]) = _call.target.call{value: val}(_call.callData); if (!success) revert CallFailed(); unchecked { ++i; } } // Finally, make sure the msg.value = SUM(call[0...i].value) if (msg.value != valAccumulator) revert CallFailed(); }
Manual Review
Add requiresApprovedCaller
modifier to payableCall()
function
function payableCall(PayableCall[] calldata calls) public payable requiresApprovedCaller returns (bytes[] memory returnData)
Access Control
#0 - c4-pre-sort
2023-10-08T14:32:43Z
0xA5DF marked the issue as duplicate of #888
#1 - c4-pre-sort
2023-10-08T14:40:34Z
0xA5DF marked the issue as sufficient quality report
#2 - c4-judge
2023-10-26T11:31:39Z
alcueca marked the issue as satisfactory
🌟 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-
11.4657 USDC - $11.47
In the BranchPort.sol, the function addStrategyToken()
lacks duplicate check while adding token into strategyTokens Array
Duplicate token Addresses can pushed multiple times to the strategyTokens
Array.
Add Duplicate check if token Address already added to the Array.
if(isStrategyToken[_token]) revert ("AlreadyAddedStrategyToken");
function addStrategyToken(address _token, uint256 _minimumReservesRatio) external override requiresCoreRouter { if (_minimumReservesRatio >= DIVISIONER || _minimumReservesRatio < MIN_RESERVE_RATIO) { revert InvalidMinimumReservesRatio(); } + if(isStrategyToken[_token]) revert AlreadyAddedStrategyToken(); strategyTokens.push(_token); getMinimumTokenReserveRatio[_token] = _minimumReservesRatio; isStrategyToken[_token] = true; emit StrategyTokenAdded(_token, _minimumReservesRatio); }
#0 - c4-pre-sort
2023-10-15T13:08:26Z
0xA5DF marked the issue as sufficient quality report
#1 - c4-judge
2023-10-21T12:41:51Z
alcueca marked the issue as grade-b