The NativeNode can't receive the Eth from the beacon chain validators, which breaks the Native Restaking functionality of the protocol and user lose their ETH of his validator.
Proof of Concept
User can use Native Restaking on Karak to restake their ETH from their beacon chain validator, it use the NativeNode address as a withdrawal address, created from a NativeVault. The NativeNiode doesn't have fallback() or receive() functions and therefore cannot receive the ETH sended from the validator.
On the beacon chain validator, when user set the withdrawal address, he can't change it, and because the NativeNode can't receive ETH, the user user lose his funds.
POC
You can see this Poc with the NativeNode and a modified NativeNode with fallback() and receive() functions.
The logs of the Poc:
-------------- NativeNode --------------
Balance Ether: 0
Balance Ether After Call: 0
-------------- NativeNode with fallback() and receive() --------------
Balance Ether: 0
Balance Ether After Call: 3000000000000000000
You can add this PoC to the ./test/nativeRestaking/nativeVault.t.sol :
function test_sendEtherToNativeNode() public {
//Setup
NativeVault vaultContract;
DSSContract dss = new DSSContract();
// Give Eth to Bob
address bob = address(500);
vm.deal(bob, 20 ether);
vm.startPrank(address(dss));
core.registerDSS(100000000000000000000);
vm.stopPrank();
// Setup NativeNode implementation
address nativeNodeImpl = address(new NativeNode());
// Deploy Vaults
VaultLib.Config[] memory vaultConfigs = new VaultLib.Config[](1);
vaultConfigs[0] = VaultLib.Config({
asset: Constants.DEAD_BEEF,
decimals: 18,
operator: operator,
name: "NativeTestVault",
symbol: "NTV",
extraData: abi.encode(address(manager), slashStore, address(nativeNodeImpl))
});
vm.startPrank(operator);
IDSS dssInterface = IDSS(address(dss));
core.registerOperatorToDSS(dssInterface, bytes(""));
IKarakBaseVault[] memory vaults = core.deployVaults(vaultConfigs, address(0));
vaultContract = NativeVault(address(vaults[0]));
vm.stopPrank();
vm.startPrank(bob);
// Try send ether on a NativeNode
address addrNativeNode = vaultContract.createNode();
uint256 natNodeBal = addrNativeNode.balance;
console.log("-------------- NativeNode --------------");
console.log("Balance Ether: %s", natNodeBal);
(bool success, bytes memory data) = addrNativeNode.call{value: 3 ether}("");
natNodeBal = addrNativeNode.balance;
console.log("Balance Ether After Call: %s", natNodeBal);
// Try send ether on a CustomNativeNode with fallback() and receive()
NativeNodeReceive natNodeReceive = new NativeNodeReceive();
uint256 natNodeBalReceive = address(natNodeReceive).balance;
console.log("-------------- NativeNode with fallback() and receive() --------------");
console.log("Balance Ether: %s", natNodeBalReceive);
(bool success2, bytes memory _data) = address(natNodeReceive).call{value: 3 ether}("");
natNodeBalReceive = address(natNodeReceive).balance;
console.log("Balance Ether After Call: %s", natNodeBalReceive);
vm.stopPrank();
}
Also add this on the top of thefile import "../../src/NativeNodeReceive.sol";
Also copy the NativeNode contract and rename it NativeNodeReceive, add theses line at the end of the contract :
Lines of code
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeNode.sol#L17
Vulnerability details
Impact
The
NativeNode
can't receive the Eth from the beacon chain validators, which breaks the Native Restaking functionality of the protocol and user lose their ETH of his validator.Proof of Concept
User can use Native Restaking on Karak to restake their ETH from their beacon chain validator, it use the
NativeNode
address as a withdrawal address, created from aNativeVault
. TheNativeNiode
doesn't havefallback()
orreceive()
functions and therefore cannot receive the ETH sended from the validator.On the beacon chain validator, when user set the withdrawal address, he can't change it, and because the
NativeNode
can't receive ETH, the user user lose his funds.POC
You can see this Poc with the
NativeNode
and a modified NativeNode withfallback()
andreceive()
functions. The logs of the Poc:You can add this PoC to the
./test/nativeRestaking/nativeVault.t.sol
:Also add this on the top of thefile
import "../../src/NativeNodeReceive.sol";
Also copy theNativeNode
contract and rename itNativeNodeReceive
, add theses line at the end of the contract :Now execute this command:
forge test --mt test_sendEtherToNativeNode -vvv
Tools Used
Manual Review
Recommended Mitigation Steps
Add
fallback()
or/andreceive()
functions in theNativeNode
.Assessed type
ETH-Transfer