xanoutas/solidity-security-findings huggingface dataset:
Invalid slash store validation makes it possible for operator to dodge slashing
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L46-L79
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/CoreLib.sol#L89-L116
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/CoreLib.sol#L118-L147
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L161-L168
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L299-L318
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/SlasherLib.sol#L134-L139
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L308


# Vulnerability details

## Impact
In the `Core.sol` file the operator has the ability to create native vaults which they can later register to a DSS which will have the ability to slash the operator if they are not cooperating. However when creating a vault the operator can create a vault in such way that when the DSS tries to slash their asset it will revert. The operator can achieve that because when creating a native vault the operator has the ability to specify arbitrary `_extraData` from which the `slashStore` is decoded and which is later assigned to `self.slashStore` in the native vault as can be seen here:
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L46-L79
```
    function initialize(
        address _owner,
        address _operator,
        address _depositToken,
        string memory _name,
        string memory _symbol,
        bytes memory _extraData
    ) external initializer {
        _initializeOwner(_owner);
        __Pauser_init();

        if (_depositToken != Constants.DEAD_BEEF) revert DepositTokenNotAccepted();

        (address manager, address slashStore, address nodeImplementation) =
            abi.decode(_extraData, (address, address, address));

        if (manager == address(0) || slashStore == address(0) || nodeImplementation == address(0)) revert ZeroAddress();
        _grantRoles(manager, Constants.MANAGER_ROLE);

        NativeVaultLib.Storage storage self = _state();
        VaultLib.Config storage config = _config();

        config.asset = _depositToken;
        config.name = _name;
        config.symbol = _symbol;
        config.decimals = 18;
        config.operator = _operator;
        config.extraData = _extraData;

        self.slashStore = slashStore;
        self.nodeImpl = nodeImplementation;

        emit NativeVaultInitialized(_owner, manager, _operator, slashStore);
    }
```
which is called from the
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/CoreLib.sol#L106-L107
```
        IKarakBaseVault vault = cloneVault(salt);
        vaul
The manager of a `NativeVault` can prevent a user to withdraw their funds during a certain time.
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L334-L336
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L282


# Vulnerability details

## Impact

An operator can pause the `NativeNode::withdraw()` function which always revert when `finishWithdrawal()` is called and thus prevent the user from withdrawing his ETH.

## Proof of Concept

When an operator want to create a `NativeVault`, he call the `deployVaults()` function on the `Core` contract with a custom config struct to give informations for the deployment. The `extraData` params is used to give the `manager`, `slahsStore` and `nodeImplementation` addresses on the `initialize()` function of the `NativeVault`.

The operator set a `manager` role which can be useful for giving authority on some functions for a custom vault developed for specifics purposes.
We can see on the `NativeVault`, the owner and also the manager can [pause](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L334-L336) the `NativeNode` functions:

```solidity
    function pauseNode(INativeNode node, uint256 map) external onlyRolesOrOwner(Constants.MANAGER_ROLE) {
        node.pause(map);
    }
```

If the manager pause the `withdraw()` function on the `NativeNode`, it create a DoS of the withdrawal process, because when the user try to finalize a withdrawal, the call will always [revert](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L282).

We can also note than also when the `withdraw()` function is paused, it's impossible to make a snapshot of the `NativeVault`.

At the end, the protocol can unpause the `withdraw()` function and revoke the manager privilege on the `NativeVault` to let the user withdraw, this issue is considered as a temporary freezing of funds.
Note that if the administrator/team needs to revoke the manager privilege, the functionality of the custom manager authority on a custom vault is broken.

## Tools Used

Manual Review

## Recommended Mitigation Steps
In my opinion you can delete the `whenFunctionNotPaused` modifier on the `NativeNode::withdraw()` function to avoid potentials malicious behavior of the manager role.


## Assessed type

Context
Operators can stake vaults without being registered in the DSS
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L146
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L130
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L113


# Vulnerability details

## Impact
If a DSS wants to slash a vault's operator, then this operator must be registered within the DSS. This is validated in the [requestSlashing function](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L228) using the `checkIfOperatorIsRegInRegDSS` check. However, is it possible for a vault to be staked in a DSS without the operator of the vault been registered in the DSS. Therefore, the DSS will not be able to slash this vault.

## Proof of Concept
When requesting a stake update the function `requestUpdateVaultStakeInDSS` [validates](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/Operator.sol#L128) that the operator is registered in the DSS. However, the operator can request to update the stake when he is registered in the DSS, call the function `unregisterOperatorFromDSS` which does not validate if the operator has pending requests and then will unregister the operator from the DSS. Finally, the operator can call the function `finalizeUpdateVaultStakeInDSS` which [does not validates](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/Operator.sol#L115) that the operator of the vault being finalized is registered in the DSS. It is important to note that not even the hook call within `finalizeUpdateVaultStakeInDSS` will prevent this operation because `ignoreFailure` is set to [true](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/Operator.sol#L128). 

## Tools Used
Manual Review

## Recommended Mitigation Steps
Validate in `finalizeUpdateStakeInDSS` that the vault's operator which stake is being finalized is registered in the DSS.


## Assessed type

Other
a malicious user can submit a invalid snapshot
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L112
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L149
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L218


# Vulnerability details

vulnerability details

the snapshot function is used by a nativenodeowner to keep the NativeNode aware of the balance changes on the beacon chain. NativeVault updates the node owner's shares based on the balance changes on their NativeNode and the beacon chain balance of the validators, which in turn changes the amount the node owner has staked into an Operator, affecting the rewards given to them, anyone can start a snapshot for the user the problem with this is anyone can submit a manipulated snapshot and the nativenode owner wont be able to provide the valid snapshot
until the snapshot is expired (7 days)  due to  checks in nativevault.sol 

if (validatorDetails.lastBalanceUpdateTimestamp >= node.currentSnapshotTimestamp) {
                revert ValidatorAlreadyProved();

 if (node.lastSnapshotTimestamp + Constants.SNAPSHOT_EXPIRY > block.timestamp) {
            revert SnapshotNotExpired();
        }

impact

an incorrect snapshot could lead to decisions based on inaccurate data. native node owners can be unfairly penalized/slashed based on incorrect data 

PROOF OF CONCEPT

*A user submits a malicious snapshot for a node owner
*The node owner sees it and tries to submit the valid snapshot
*but the transaction reverts because the function doesn't allow a new snapshot if there is already a pending one
*After the transaction is completed, the user again tries to submit the valid snapshot, but the function reverts again due to checks in NativeVault.sol, which do not allow a new snapshot if the last snapshot has not expired or if the validator has already proven it.

Recommended Mitigation Steps

only allow the nativenode owner to submit a snapshot for their nodes





## Assessed type

Context
The operator can still access `Core::finalizeUpdateVaultStakeInDSS()` even after unregistering from the DSS.
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L146


# Vulnerability details

## Impact
- This vulnerability was not resolved in the previous audit, despite being marked as fixed. This is `M1` from `audit/core/Renascence - Karak Core Audit Report.pdf` .

- Unregistered Operator can call `finalizeUpdateVaultStakeInDSS` from Core.sol which must only Callable for the registered Operator.

## Proof of Concept

- This vulnerability was not resolved in the previous audit, despite being marked as fixed. This is `M1` from `audit/core/Renascence - Karak Core Audit Report.pdf`

## Tools Used
- Manual Review

## Recommended Mitigation Steps

- If every DSS ensures its own access control that the operator calling Core.finalizeUpdateVaultStakeInDSS() is registered with the DSS, then Core.finalizeUpdateVaultStakeInDSS() should set canFail = false to avoid recording an incorrect state in Core.sol. In the case where DSSs rely on Core.sol to perform an access control check on the operator,`Core::finalizeUpdateVaultStakeInDSS()` must have an onlyOperatorRegisteredToDSS modifier.

```diff
 function finalizeUpdateVaultStakeInDSS(Operator.QueuedStakeUpdate memory queuedStake)
        external
        nonReentrant
        whenFunctionNotPaused(Constants.PAUSE_CORE_FINALIZE_STAKE_UPDATE)       
{
+        isOperatorRegisteredToDSS(queuedStake.operator, queuedStake.updateRequest.dss);
```








## Assessed type

Access Control
Race Condition between Withdrawals and Slashing 
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/main/src/Vault.sol#L125
https://github.com/code-423n4/2024-07-karak/blob/main/src/Vault.sol#L157
https://github.com/code-423n4/2024-07-karak/blob/main/src/entities/SlasherLib.sol#L129


# Vulnerability details

## Impact
An operator can create a Race Condition between his withdrawal request and the DSS's slash request, allowing him to avoid slashing after a slashable offense. This is possible due to the slash delay, `SLASHING_VETO_WINDOW`, imposed on the DSS. The comment in the vault contract states, `"To prevent someone from sitting on queuedWithdrawals to front-run a slashing, DSS shouldn't consider stakes queued in withdrawals."` Unfortunately, an operator can, after joining a DSS, create a withdrawal request via `startRedeem()`. By doing this, the DSS has more than likely counted all of the operator's stake since the `queuedWithdrawals` is created after joining the DSS. 

The operator's withdrawal request takes 9 days to process while the DSS slash request takes 2 days. 

```solidity
 uint256 public constant SLASHING_WINDOW = 7days;

...snip...

uint256 public constant SLASHING_VETO_WINDOW = 2 days;

...snip...

uint256 public constant MIN_WITHDRAWAL_DELAY = SLASHING_WINDOW + SLASHING_VETO_WINDOW;

```

On its face, this should be fine but if an operator commits the slashable offense with less than 2 days left for his withdrawal request to finish processing the DSS will be unable to slash him in time since the DSS has to wait at least two days before slashing.

```solidity
function finalizeSlashing(CoreLib.Storage storage self, QueuedSlashing memory queuedSlashing) external {

        bytes32 slashRoot = calculateRoot(queuedSlashing);

        if (!self.slashingRequests[slashRoot]) revert InvalidSlashingParams();

        if (queuedSlashing.timestamp + Constants.SLASHING_VETO_WINDOW > block.timestamp) {

            revert MinSlashingDelayNotPassed();

        }

...snip...

```

As a result, an operator can create a Race Condition between his withdrawal request and the DSS's slash request, allowing him to avoid slashing after a slashable offense.

## Proof of Concept

Operator after registering with DSS creates a withdrawal request via `startRedeem()`.

Operator waits for 9 days.

Operator performs a slashable offense. 

DSS detects slashable offense committed by the operator and calls. `requestSlashing()`.

Operator calls `finishRedeem()` to withdraw his assets

DSS was unable to successfully slash the Operator before his withdrawal request was executed because the DSS had to wait `SLASHING_VETO_WINDOW ` or 2 days. 

## Recommended Mitigation Steps
When a DSS submits a Slash Request the operator's Withdrawal Request should be cancelled or rescheduled. 


## Assessed type

Timing
It is possible to bypass validateWithdrawalCredentials
Audit: 2024-07-karak-findings
Severity: HIGH

# 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](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L168C14-L168C43), or having any validator connected to the node.

After a user creates a node, they can directly call  [startSnapshot](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L112C14-L112C27), for that node, before verifying them self with [validateWithdrawalCredentials](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L168C14-L168C43); this is meant to have no effects (As highlighted in the [tests](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/test/nativeRestaking/nativeVault.t.sol#L221) provided). But there is a way to force the  [startSnapshot](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L112C14-L112C27) 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](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L112C14-L112C27) function only verifies that a node exists for *msg.sender*:
```
    function startSnapshot(bool revertIfNoBalanceChange)
        external
        nonReentrant
        nodeExists(msg.sender)
        whenFunctionNotPaused(Constants.PAUSE_NATIVEVAULT_START_SNAPSHOT)
    {
        _startSnapshot(_state().ownerToNode[msg.sender], revertIfNoBalanceChange, 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](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L168C14-L168C43), their *remainingProofs* will be 0, when creating the new snapshot (as the validators gets added by validating the credentials):
```
        NativeVaultLib.Snapshot memory snapshot = NativeVaultLib.Snapshot({
            parentBeaconBlockRoot: _getParentBlockRoot(uint64(block.timestamp)),
            nodeBalanceWei: nodeBalanceWei,
            balanceDeltaWei: 0,
            remainingProofs: node.activeValidatorCount
        });
```
Meaning that the [_updateSnapshot](https://github.com/code-42
The operator can create a `NativeVault` that can be silently unslashable.
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/SlasherLib.sol#L134-L138
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L308


# Vulnerability details

## Impact
An operator can create a `NativeVault` which always revert when `slashAssets()` is call and make the vault unslashable.

## Proof of Concept

When an operator want to create a `NativeVault`, he call the `deployVaults()` function on the `Core` contract with a custom config struct to give informations for the deployment. The `extraData` params is used to give the `manager`, `slahsStore` and `nodeImplementation` addresses on the `initialize()` function of the `NativeVault`.

When an asset is allowed on the protocol, a `slashingHandler` address is associated with the asset address on the `assetSlashingHandlers` mapping.

`NativeVault` is used to make native restaking with the ETH of Beacon Chain validators of users. When a slashing is executed, the address of `assetSlashingHandlers` mapping is inserted as a params in [the call](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/entities/SlasherLib.sol#L134-L138) `slashAssets()` :

```solidity
    for (uint256 i = 0; i < queuedSlashing.vaults.length; i++) {
        IKarakBaseVault(queuedSlashing.vaults[i]).slashAssets(
            queuedSlashing.earmarkedStakes[i],
            self.assetSlashingHandlers[IKarakBaseVault(queuedSlashing.vaults[i]).asset()]
        );
    }
```

Then the function make this [verification](https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/NativeVault.sol#L308) with the input address of `slashingHandler`:
```solidity
    if (slashingHandler != self.slashStore) revert NotSlashStore();
```

If the operator, during the initialization, insert a `slashStore` address which is different from the `assetSlashingHandlers` address for ETH, the call on the `NativeVault` will always revert and make the vault slash impossible.

### POC 
You can add this PoC to the `./test/nativeRestaking/nativeVault.t.sol` :

```solidity

    function test_createUnslashableVault() public {
        //Setup
        vm.warp(1718549030);
        NativeVault unslashableVault;
        address badSlashStore = address(666);
        DSSContract dss = new DSSContract();

        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),
Vulnerability in Vault Redemption Process Allows Malicious Operators to Reduce Slashing Penalties
Audit: 2024-07-karak-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L220
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Core.sol#L235
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Vault.sol#L125
https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Vault.sol#L157


# Vulnerability details

## Impact
The current implementation allows a malicious operator to exploit the staking and redemption mechanisms. By staking a significant portion of their own vault (e.g., 50%) and then initiating the `startRedeem` process. Suppose after day 8 a DSS wants to slash about 80% of the vault but will not be able to do that because of the `SLASHING_VETO_WINDOW`. Till the veto period ends the operator can withdraw its stake and system will not be able to slash 80% but will be able to slash only 50% tokens.
This loophole allows the operator to withdraw funds before the slashing can be executed, effectively reducing the penalty. Add a mechanism where if the slashing request is in pending then don't allow to withdraw from that vault until slashing happens or Veto period finishes.

1. Malicious Operator Stake: The operator stakes a significant amount in their own vault, say 50%.
2. Initiate Redemption: The operator calls `startRedeem()` to begin the redemption process.
3. Malicious Activity Found: After 8 days, the operator found in malicious activity.
4. DSS Attempts Slashing: The DSS identifies the malicious behavior and initiates a slashing request for 70%.
5. Redemption Completion: However, due to the SLASHING_VETO_WINDOW, the DSS cannot execute the slashing immediately.
6. Withdrawal of Funds: The operator completes the redemption calling `finishRedeem` and withdraws their staked amount, leaving insufficient funds for the full slashing amount.

## Proof of Concept
![Screenshot 2024-07-31 010347](https://github.com/user-attachments/assets/ab2a8721-9970-4e94-900d-1555bfef73ca)
![image](https://github.com/user-attachments/assets/26b45229-7c2e-49bd-bc1d-efd11381d911)

## Tools Used
Manual Review

## Recommended Mitigation Steps
Block Withdrawals During Slashing Pending: Implement a mechanism that blocks withdrawals from the vault when a slashing request is pending. This would ensure that operators cannot withdraw funds once malicious activity is detected, allowing the DSS to execute the required slashing.


## Assessed type

Timing