Platform: Code4rena
Start Date: 18/10/2023
Pot Size: $36,500 USDC
Total HM: 17
Participants: 77
Period: 7 days
Judge: MiloTruck
Total Solo HM: 5
Id: 297
League: ETH
Rank: 59/77
Findings: 1
Award: $28.60
🌟 Selected for report: 1
🚀 Solo Findings: 0
28.5994 USDC - $28.60
"According to the GEB framework, the proxy contracts (ODProxy
) are designed to interact with the Safe Manager (ODSafeManager
) through the Proxy Action contract (BasicActions
). The pivotal function, allowSAFE()
, is responsible for granting an address the capability to manage the Safe. Unfortunately, the BasicActions
contract lacks the implementation of the allowSAFE()
function. Consequently, the proxy contract is unable to execute allowSAFE()
, leading to the inaccessibility of several critical functions for authorized users.
The functionality of essential operations such as modifySAFECollateralization()
, transferCollateral()
, transferInternalCoins()
, quitSystem()
, enterSystem()
, moveSAFE()
, removeSAFE()
, and protectSAFE()
is currently halted due to the inability to allow users to manage the Safe.
In addition to the absent allowSAFE()
implementation, the following functions are also not yet implemented in the BasicActions
contract and these functions are not directly executable by proxy contract: allowHandler()
, modifySAFECollateralization()
, transferCollateral()
, transferInternalCoins()
, quitSystem()
, enterSystem()
, moveSAFE()
, removeSAFE()
, and protectSAFE()
."
Place the following test file in test/nft/anvil/
and run forge t --fork-url http://127.0.0.1:8545 --match-path test/nft/anvil/NFTTestAnvil.t.sol -vvv
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.19; import 'forge-std/console.sol'; import {AnvilFork} from '@test/nft/anvil/AnvilFork.t.sol'; import {Vault721} from '@contracts/proxies/Vault721.sol'; import {IODSafeManager} from '@interfaces/proxies/IODSafeManager.sol'; import {ODProxy} from '@contracts/proxies/ODProxy.sol'; contract NFTTestAnvil is AnvilFork { function test_setup() public { assertEq(totalVaults, vault721.totalSupply()); checkProxyAddress(); checkVaultIds(); } // Function to test open safe and allow safe with direct call function test_allowSafeDirectCall() public { address _proxy = proxies[0]; bytes32 cType = cTypes[0]; address user = users[0]; vm.startPrank(user); uint256 safeId = safeManager.openSAFE(cType,_proxy); IODSafeManager.SAFEData memory sData = safeManager.safeData(safeId); assertEq(_proxy,sData.owner); // allowSAFE call will fail vm.expectRevert(IODSafeManager.SafeNotAllowed.selector); safeManager.allowSAFE(safeId, user, 1); vm.stopPrank(); } // Function to test open safe and allow safe with proxy delegation call function test_allowSafeWithProxyExecute() public { address _proxy = proxies[0]; bytes32 cType = cTypes[0]; address user = users[0]; vm.startPrank(user); uint256 safeId = openSafe2(cType,_proxy); IODSafeManager.SAFEData memory sData = safeManager.safeData(safeId); assertEq(_proxy,sData.owner); // allowSAFE call will fail vm.expectRevert(); allowSafe(_proxy, safeId, user, 1); vm.stopPrank(); } function openSafe2(bytes32 _cType, address _proxy) public returns (uint256 _safeId) { bytes memory payload = abi.encodeWithSelector(basicActions.openSAFE.selector, address(safeManager), _cType, _proxy); bytes memory safeData = ODProxy(_proxy).execute(address(basicActions), payload); _safeId = abi.decode(safeData, (uint256)); } function allowSafe(address _proxy, uint256 _safe, address _usr, uint256 _ok) public { bytes memory payload = abi.encodeWithSelector(safeManager.allowSAFE.selector,_safe, _usr, _ok); ODProxy(_proxy).execute(address(safeManager), payload); } }
Here you can see, both call to the allowSAFE()
are failing, ie proxy contract cannot able to allow an address to manage the safe.
See the second test case, when we are calling the allowSAFE()
with delegatecall
the context of the target(ODSafeManager
) has changed and the call get failed.
Manual Review and Foundry
Implement necessary functions in the BasicActions
contract to execute necessary functions in the ODSafeManager
contract.
call/delegatecall
#0 - c4-pre-sort
2023-10-26T19:38:33Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-10-26T19:38:46Z
raymondfam marked the issue as duplicate of #380
#2 - c4-judge
2023-11-02T18:17:42Z
MiloTruck marked the issue as not a duplicate
#3 - c4-judge
2023-11-02T18:18:20Z
MiloTruck marked the issue as duplicate of #294
#4 - c4-judge
2023-11-08T00:21:48Z
MiloTruck changed the severity to 2 (Med Risk)
#5 - c4-judge
2023-11-08T00:21:53Z
MiloTruck marked the issue as satisfactory
#6 - c4-judge
2023-11-08T00:22:02Z
MiloTruck marked the issue as selected for report
#7 - MiloTruck
2023-11-08T00:23:28Z
Since BasicActions.sol
does not have a function to call allowSafe()
, users will not be able to interact with ODSafeManager
through their proxies.
However, since this can be addressed operationally by deploying another implementation contract, there isn't any permanent DOS of the protocol's functionality. Therefore, medium severity is appropriate.