Closed howlbot-integration[bot] closed 2 months ago
would reclassify as a non-issue, comments on why should come soon from @karan-andalusia
This is by design since even in this case where the user might not have any active validators and use self destruct to deposit some amount of ETH on the node, that ETH is still slashable and provides the same economic security. Even if the user has active validators they can still deposit as much ETH to the node as they want using the self destruct workaround. However, they can only withdraw the ETH valued by the shares that have been minted to them which in turn is slashable.
MiloTruck marked the issue as unsatisfactory: Invalid
As mentioned by the sponsor, this is by design.
If the node owner has ETH in his native node but the ETH isn't staked in a validator, there is no issue as his balance is still slashable. The only impact is the node owner causes himself to lose out yield from ETH staking.
Lines of code
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L459 https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L467 https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L481
Vulnerability details
Impact
It is possible to join a vault, by obtaining shares of it, without having to call validateWithdrawalCredentials, or having any validator connected to the node.
After a user creates a node, they can directly call startSnapshot, for that node, before verifying them self with validateWithdrawalCredentials; this is meant to have no effects (As highlighted in the tests provided). But there is a way to force the startSnapshot function to mint new shares to the user, letting them join the vault without having to verify their withdraw credentials or having any validators to their name.
Proof of Concept
The startSnapshot function only verifies that a node exists for msg.sender:
Meaning and after a user deploys a node they can call this function without any further limitations.
If they call it before validating their credentials with validateWithdrawalCredentials, their remainingProofs will be 0, when creating the new snapshot (as the validators gets added by validating the credentials):
Meaning that the _updateSnapshot function called at the end of _startSnapshot, will take the first branch of the if statement:
Since it is expected that the node has accumulated no ETH yet, this will delete the snapshot, and when calling _updateBalance nothing will happen (as it will be called with assets = 0):
It is possible to make it so that the node has a balance greater than 0 when calling startSnapshot this way (even without connecting it to any validators). Meaning that the _updateBalance function will call _increaseBalance, and the user will get a proportional amount of shares of the vault, without having verified their credentials and even without controlling any validators on the Beacon Chain.
Although the NativeNode contract is not payable, a user can call selfdestruct on a purposely created contract, and transfer ETH directly into the node, meaning that when they call startSnapshot, the balance will be greater than 0, and they will get shares, bypassing validateWithdrawalCredentials.
selfdestruct is being deprecated, but that is not an issue. As highlighted in EIP-6780, the ability to transfer ETH to an arbitrary accounts will remain:
Here is a foundry script that you can run. Place it in the
/test/nativeRestaking
directory to preserve dependencies:Assessed type
Access Control