Platform: Code4rena
Start Date: 11/11/2022
Pot Size: $90,500 USDC
Total HM: 52
Participants: 92
Period: 7 days
Judge: LSDan
Total Solo HM: 20
Id: 182
League: ETH
Rank: 40/92
Findings: 3
Award: $189.50
🌟 Selected for report: 0
🚀 Solo Findings: 0
61.5174 USDC - $61.52
Detailed description of the impact of this finding.
The implementation of executeAsSmartWallet()
is too powerful. It allows a dao to drain any node runner's wallet anytime.
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept. Let's say Dao's address is A, and a node runner's address is B. Deploy the following contract at address C. Suppose there are 5 eth in the wallet.
Basically, Dao just needs to call from contract at address A the following line (if A is an EOA, then dao can just change to a new Dao address, which is a contract):
executeAsSmartWallet(B, A, abi.encodeWithSelector(SendMeETH.thanks.selector, 5 eth);
In other words, Dao can ask B's smart wallet to execute a function of A (say thanks()) while sending A 5 eth (or whatever the ETH balance of B's smart wallet is).
Remix
In summary, a dao should not be able to ask the smart wallet to call an arbitrary external contract and function, this is very risky. This not only makes the dao overly powerful, but also a huge security concern in case the dao's address is compromised.
#0 - c4-judge
2022-11-20T15:04:06Z
dmvt marked the issue as unsatisfactory: Overinflated severity
#1 - dmvt
2022-11-20T21:23:50Z
The quality of the report in #106 has changed my mind.
#2 - c4-judge
2022-11-20T21:24:08Z
dmvt marked the issue as duplicate of #106
#3 - c4-judge
2022-11-20T21:24:19Z
dmvt marked the issue as partial-50
#4 - c4-judge
2022-11-20T21:24:27Z
dmvt changed the severity to 2 (Med Risk)
#5 - c4-judge
2022-11-29T22:59:01Z
dmvt marked the issue as satisfactory
75.9475 USDC - $75.95
Judge has assessed an item in Issue #16 as M risk. The relevant finding follows:
AQ6: https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/LiquidStakingManager.sol#L356 This function provides too much power to Dao, if the dao calls the function, then he can be the node runner of each smart wallet and then call withdrawETHForKnot to drain each smart wallet.
#0 - c4-judge
2022-11-29T15:13:24Z
dmvt marked the issue as duplicate of #383
#1 - c4-judge
2022-12-02T22:08:16Z
dmvt marked the issue as partial-25
🌟 Selected for report: 0xSmartContract
Also found by: 0x4non, 0xNazgul, 0xRoxas, 0xdeadbeef0x, 0xmuxyz, 9svR6w, Awesome, Aymen0909, B2, Bnke0x0, CloudX, Deivitto, Diana, Franfran, IllIllI, Josiah, RaymondFam, ReyAdmirado, Rolezn, Sathish9098, Secureverse, SmartSek, Trust, Udsen, a12jmx, aphak5010, brgltd, bulej93, c3phas, ch0bu, chaduke, chrisdior4, clems4ever, cryptostellar5, datapunk, delfin454000, fs0c, gogo, gz627, hl_, immeas, joestakey, lukris02, martin, nogo, oyc_109, pashov, pavankv, peanuts, pedr02b2, rbserver, rotcivegaf, sahar, sakman, shark, tnevler, trustindistrust, zaskoh, zgo
52.0338 USDC - $52.03
GA1: https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/LPTokenFactory.sol#L18-L22 It is better NOT to pass the implementation as an argument, which makes it hard to verify and trust its correctness. Use the following code instead:
constructor(address _lpTokenImplementation) { lpTokenImplementation = address(new LPToken()); }
It should be
bytes[] memory _blsPublicKeyOfKnots = new bytes[1];
GA3: In LiquidStakingManager.sol#L805
, in many occasions, it calls the execute()
function in the smart wall to call a function in the ``getTransctionRouter()''. It might be better to define that function (or a wrapper) in OwnableSmartWallet explicit and call it instead.
GA4: https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/LiquidStakingManager.sol#L343 A node runner should be able to withdraw all the balance in the smart wallet instead of a fix 4eth in case some more ETH has been sent to the smart wallet by accident.
GA5: https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/LiquidStakingManager.sol#L829
sETH
was received in this line from the stakehouse to the smartWallet first, then transferred to the LiquidStakingManger, and then finally transferred to the syndicate in the account of the smartwallet. The accounting can be done more efficiently, by receiving the sETH
to the syndicate directly and then gives credit to the corresponding smartwallet/blsPubickey directly.
AQ6: https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/LiquidStakingManager.sol#L356
This function provides too much power to Dao, if the dao calls the function, then he can be the node runner of each smart wallet and then call withdrawETHForKnot
to drain each smart wallet.
#0 - c4-judge
2022-11-29T15:14:40Z
dmvt marked the issue as grade-b