xanoutas/solidity-security-findings huggingface dataset:
BaseSettlement contract has _Settlement_init Function is public but should be internal
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/solidity/settlement/contracts/BaseSettlement.sol#L54-L74


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
Title: BaseSettlement contract has _Settlement_init Function is public but should be internal
•	Severity: Medium
•	Impact: The _Settlement_init function in the BaseSettlement contract is marked with public visibility, which allows it to be called by external contracts and users.
•	Status: Unresolved
•	File: BaseSettlement.sol
•	Lines Affected: 54-74

The _Settlement_init function in the BaseSettlement contract is marked with public visibility, which allows it to be called by external contracts and users. However, the function name starts with a prefixed underscore (_), which conventionally indicates that the function is intended for internal use only. The current visibility setting can lead to unintended exposure of this function, potentially allowing unauthorized initialization or reconfiguration of the contract’s critical parameters.

If the _Settlement_init function remains public, external actors could exploit it to reinitialize or manipulate the contract, leading to potential security risks such as unauthorized access or modification of roles, validators, and other critical configuration settings. This could undermine the integrity of the contract’s operation and expose the system to attacks.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

The following code demonstrates the _Settlement_init function currently marked as public:
```sol
function _Settlement_init(
    string memory _chain_name,
    uint256 _chain_id,
    address _owner,
    address[] memory _managers,
    uint256 _required_validators,
    address _signature_verifier
) public {
    __Ownable_init(_owner);
    __UUPSUpgradeable_init();
    _grantRole(DEFAULT_ADMIN_ROLE, _owner);

    for (uint256 i = 0; i < _managers.length; i++) {
        _grantRole(MANAGER_ROLE, _managers[i]);
    }

    chain_id = _chain_id;
    contract_chain_name = _chain_name;
    required_validators = _required_validators;
    signature_verifier = ISettlementSignatureVerifier(_signature_verifier);
}
```
An attacker could create a contract to call this function and potentially reinitialize or misconfigure the contract:
```sol
// Attacker's script
contract SettlementExploit {
    function exploit(BaseSettlement targetContract) external {
        targetContract._Settlement_init(
            "FakeChain",
            9999,
            msg.sender,
            new address ,
            1,
            address(0)
        );
    }
}
```

## Tools Used
Manual review.

## Recommended Mitigation Steps
To mitigate this issue, the visibility of the _Settlement_init function should be changed to internal to restrict its access to within the contract itself or by de
Excessive Authority Granted to Managers in the `ckr_btc.cairo` Contract Presents Significant Management Risks
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/ckr_btc.cairo#L134-L218


# Vulnerability details

In the `ckr_btc.cairo` contract, managers possess broad authority and can execute all functions except `upgrade()`. This level of access contrasts with typical Solidity practices, where such functions would require `owner` privileges.

One of the primary concerns is that any existing manager has the ability to add new managers. This unchecked ability to expand the number of managers can lead to an uncontrolled increase in the number of authorized managers, creating a potential security risk. Without additional checks or approval mechanisms, this design flaw could be exploited, leading to a dilution of control and increased risk of unauthorized actions.

Furthermore, managers also have the ability to designate operator roles. Operators, in turn, have the authority to mint and burn tokens, which compounds the risk if these roles are not properly managed. This level of access could easily lead to a situation where control over critical functions is decentralized in a manner that might not have been intended by the original design.

It is unclear whether this design was intentional, but it introduces significant management risks that should be addressed.
```js
        fn add_manager(ref self: ContractState, new_manager: ContractAddress) -> bool {
            let caller = get_caller_address();
@>            assert(self.chakra_managers.read(caller) == 1, Errors::NOT_MANAGER);
            assert(self.chakra_managers.read(new_manager) == 0, Errors::ALREADY_MANAGER);


            self.chakra_managers.write(new_manager, 1);
            self
                .emit(
                    ManagerAdded {
                        operator: caller, new_manager: new_manager, added_at: get_block_timestamp()
                    }
                );
            return self.chakra_managers.read(new_manager) == 1;
        }
        fn add_operator(ref self: ContractState, new_operator: ContractAddress) -> bool {
            let caller = get_caller_address();
@>            assert(self.chakra_managers.read(caller) == 1, Errors::NOT_MANAGER);
            assert(self.chakra_operators.read(new_operator) == 0, Errors::ALREADY_OPERATOR);


            self.chakra_operators.write(new_operator, 1);
            self
                .emit(
                    OperatorAdded { new_operator: new_operator, added_at: get_block_timestamp() }
                );
            return self.chakra_operators.read(new_operator) == 1;
        }

        fn mint_to(ref self: ContractState, to: ContractAddress, amount: u256) -> bool {
            let caller = get_caller_address();
@>            assert(self.chakra_operators.read(caller) == 1, Errors::NOT_OPERATOR);
            let old_balance = self.erc20.balance_of(to);
            self.erc20.mint(to, amount);
            let new_balance = self.erc20.balance_of(to);
Improper access control on Cairo contracts for manager management
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/settlement.cairo#L248
https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/settlement.cairo#L262
https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/ckr_btc.cairo#L136
https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/ckr_btc.cairo#L150


# Vulnerability details

## Impacts
Only owners should be able to add or remove managers, as confirmed by the sponsor, and as confirmed by solidity contracts, [here](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/solidity/settlement/contracts/BaseSettlement.sol#L149C53-L149C62) and [here](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/solidity/settlement/contracts/BaseSettlement.sol#L159C56-L159C65):
```solidity
/**
* @dev Grant a manager role for address
* @notice Only owner can do this
* @param _manager The manager address
*/
function add_manager(address _manager) external
>>> onlyOwner 
 {
    grantRole(MANAGER_ROLE, _manager);
    emit ManagerAdded(msg.sender, _manager);
}
```
However, this access control is not correctly enforced in the Cairo contracts. The current implementation allows managers to add or remove other managers, which could lead to unauthorized access and management of the protocol:
```rs
// settlement.cairo

 // Managers related operations
fn add_manager(ref self: ContractState, new_manager: ContractAddress) -> bool {
    let caller = get_caller_address();
>>>    assert(self.chakra_managers.read(caller) == 1, "Caller is not a manager"); 
    assert(caller != new_manager, "Caller is a manager already");
    self.chakra_managers.write(new_manager, 1);
    self.emit(ManagerAdded {operator: caller, new_manager: new_manager, added_at: get_block_timestamp()});
    return self.chakra_managers.read(new_manager) == 1;
}

fn remove_manager(ref self: ContractState, old_manager: ContractAddress) -> bool {
    let caller = get_caller_address();
>>>    assert(self.chakra_managers.read(caller) == 1, "Caller is not a manager"); 
    self.chakra_managers.write(old_manager, 0);
    self.emit(ManagerRemoved {operator: caller,old_manager: old_manager,removed_at: get_block_timestamp()});
    return self.chakra_managers.read(old_manager) == 0;
}
```
This issue is also present in `ckr_btc.cairo` as shown [here](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/ckr_btc.cairo#L136) and [here](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/ckr_btc.cairo#L150)
## Tools Used
Manual Review

## Recommended Mitigation Steps
The access control logic should be updated to ensure that only the contract owner can manage the addi
`send_cross_chain_msg` has no access control on Ethereum
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/settlement/contracts/ChakraSettlement.sol#L117


# Vulnerability details

## Impact

After cross-chain transaction is initiated inside of `ChakraSettlementHandler`, it goes to the `ChakraSettlement` contract where an event that's monitored by the offchain services is emitted. The problem is that `send_cross_chain_msg()` that's called from the handler contract has no access control at all allowing anybody to manipulate the payload and bypass the information that was submitted by the `ChakraSettlementHandler` smart contract.

## Proof of Concept

As you can see, inside of the function `send_cross_chain_msg`, the handler address is not checked anyhow:

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/settlement/contracts/ChakraSettlement.sol#L111-120
```
  function send_cross_chain_msg(
        string memory to_chain,
        address from_address,
        uint256 to_handler,
        PayloadType payload_type,
        bytes calldata payload
    ) external {
        nonce_manager[from_address] += 1;

        address from_handler = msg.sender;

```

It only takes `msg.sender` and uses it as the `from_handler` address. The function has `external` visibility with no access control modifiers so anybody can just call it and change the payload that was sent from the handler. An attacker can, for example, put all the data that was sent by other users and just slightly change the payload blocking the successful settlement. 


## Tools Used

Manual review.

## Recommended Mitigation Steps

There should be corresponding handler address for the settlement contract initialized in the constructor of the contract that should be checked in all sensitive functions.








## Assessed type

Other
TokenRoles contract can be reinitialized
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/TokenRoles.sol#L19


# Vulnerability details

## Impact

`TokenRoles` contract is the contract that helps to add / remove operators. However, the initialization function can be called again and again allowing to reinitialize the contract which should not be the case.

## Proof of Concept

Current functionality of the initialization:

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/TokenRoles.sol#L19-23
```
    function __TokenRoles_init(address _owner, address _operator) public {
        __Ownable_init(_owner);
        _grantRole(DEFAULT_ADMIN_ROLE, _owner);
        _grantRole(OPERATOR_ROLE, _operator);
    }
```

As you can see, the function has no `initializer` modifier that allows to reinitialize the contract. Putting the `initializer()` in the implementation ensures that the storage variable alignment will be automatically correct.

## Tools Used

Manual review.

## Recommended Mitigation Steps

Add `initializer` modifier to the initialization function.


## Assessed type

Other
Missing `chain` & `handler` validation when initiating a cross-chain tx
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/solidity/handler/contracts/ChakraSettlementHandler.sol#L111


# Vulnerability details

## Impact
The missing validation of the `to_chain` and `to_handler` during cross-chain ERC20 settlement results in eventual transaction failures and also goes against the protocol requirement that these values must be valid for each other.

## Proof of Concept
In the `cross_chain_erc20_settlement()` function, the `chain` and `handler` are not validated

The function [`is_valid_handler()`](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/solidity/handler/contracts/ChakraSettlementHandler.sol#L41-L46) checks if a `handler` is valid for a given `chain`:
```solidity
    function is_valid_handler(
        string memory chain_name,
        uint256 handler
    ) public view returns (bool) {
        return handler_whitelist[chain_name][handler];
    }
```
The same goes for [`is_valid_handler()`](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/handler_erc20.cairo#L234-L236) which is used in [`handle_erc20::cross_chain_erc20_settlement()`](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/handler_erc20.cairo#L168) to validate the  `to_chain` and  `to_handler` provided during initialization of cross-chain ERC20 settlement
```solidity
    assert(self.support_handler.read((to_chain, to_handler)), 'not support handler');
```

However, in [`ChakraSettlementHandler::cross_chain_erc20_settlement()`](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/solidity/handler/contracts/ChakraSettlementHandler.sol#L111), this check is not performed:
The function just uses the `to_chain` and  `to_handler` provided as they are without performing any validations.

As such, an invalid `to_handler` for the given `to_chain` may be used which may result in failed transactions.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Validate the `to_chain` and `to_handler` in the `ChakraSettlementHandler::cross_chain_erc20_settlement()`:
```diff
        require(to_handler != 0, "Invalid to handler address");
        require(to_token != 0, "Invalid to token address");
+       require(is_valid_handler(to_chain, to_handler), "Invalid handler");
```





## Assessed type

Invalid Validation
Insufficient destination handler validation on the source chain in CharkaSettlementHandler smart contract
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/ChakraSettlementHandler.sol#L120


# Vulnerability details

## Impact

`cross_chain_erc20_settlement()` function serves as an entry for user cross-chain transactions. The problem is that the function does not anyhow validate the `to_handler` address except for address(0) check not checking its validity inside of the source chain handler.

## Proof of Concept

Current validation process looks like this:

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/ChakraSettlementHandler.sol#L120
```
require(to_handler != 0, "Invalid to handler address");
```

The function does not check validity of the handler on the destination chain even though there is `is_valid_handler()` function inside of the contract:

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/ChakraSettlementHandler.sol#L41-46
```
 /**
     * @dev Checks if a handler is valid for a given chain
     * @param chain_name The name of the chain
     * @param handler The handler address
     * @return bool True if the handler is valid, false otherwise
     */
    function is_valid_handler(
        string memory chain_name,
        uint256 handler
    ) public view returns (bool) {
        return handler_whitelist[chain_name][handler];
    }

```

So not verifying it on the source chain can lead to DoS on the destination chain and excessive gas costs being spent by the users on the execution.

From the docs:

```
The handler receiving a cross-chain message must be on the whitelist for the source chain
```

Moreover, there is the following check in the Cairo version of the contract:

https://github.com/code-423n4/2024-08-chakra/blob/main/cairo/handler/src/handler_erc20.cairo#L168
```
assert(self.support_handler.read((to_chain, to_handler)), 'not support handler');
```


## Tools Used

Manual review.

## Recommended Mitigation Steps

Add `is_valid_handler` check in the `cross_chain_erc20_settlement()`.





## Assessed type

Other
Cairo version of cross_chain_erc20_settlement() function misses address validation and amount validation
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/main/cairo/handler/src/handler_erc20.cairo#L167


# Vulnerability details

## Impact

In the `cross_chain_erc20_settlement()` function of the Starknet version of the ChakraSettlementHandler, users can submit their cross-chain transactions as well to transfer ERC20 tokens to the destination chain. The problem lies in the insufficient validation of the amount that's sent by the users.

## Proof of Concept

Take a look at the current functionality:

https://github.com/code-423n4/2024-08-chakra/blob/main/cairo/handler/src/handler_erc20.cairo#L167-172
```
 fn cross_chain_erc20_settlement(ref self: ContractState, to_chain: felt252, to_handler: u256, to_token: u256, to: u256, amount: u256) -> felt252{
            assert(self.support_handler.read((to_chain, to_handler)), 'not support handler');
            let settlement = IChakraSettlementDispatcher {contract_address: self.settlement_address.read()};
            let from_chain = settlement.chain_name();
            let token = IERC20Dispatcher{contract_address: self.token_address.read()};
            let token_burnable = IERC20MintDispatcher{contract_address: self.token_address.read()};

```

As you can see, there is no amount check as it was checked on Ethereum chain:

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/ChakraSettlementHandler.sol#L118
```
 require(amount > 0, "Amount must be greater than 0");
```

From the docs:

```
Cross-chain ERC20 settlements can only be initiated with a valid amount (greater than 0), a valid recipient address, a valid handler address, and a valid token address.
```

As this is a cross-chain protocol, it's more important to have protection from spamming attacks that can result from insufficient parameters validation affecting the Chakra network congestion. 

## Tools Used

Manual review.

## Recommended Mitigation Steps

Add `amount > 0` check in the cairo version of the contract.


## Assessed type

Other
There is no nonce increase in the handler_erc20
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/main/cairo/handler/src/handler_erc20.cairo#L167


# Vulnerability details

## Impact

In the `cross_chain_erc20_settlement()`, users submit their cross-chain transactions to transfer tokens and release them on the destination handler contract. However, as per specification, there is no nonce increase to ensure the uniqueness of the transaction ids.

## Proof of Concept

https://github.com/code-423n4/2024-08-chakra/blob/main/cairo/handler/src/handler_erc20.cairo#L167-232

As you can see, the nonce is not incremented the same way it's done in the Ethereum part of the codebase:

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/ChakraSettlementHandler.sol#L133-136
```
 {
            // Increment nonce for the sender
            nonce_manager[msg.sender] += 1;
        }
```

As per docs:

```
The nonce for each sender is incremented with each cross-chain transaction to ensure uniqueness of transaction IDs.
```

## Tools Used

Manual review.

## Recommended Mitigation Steps

Create `nonce_manager` mapping in the contract and increase the nonce for `msg.sender` with each transaction.


## Assessed type

Other
The creation of txId on the Starknet is incorrect potentially breaking compatibility with ChakraSettlementHandler
Audit: 2024-08-chakra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/main/cairo/handler/src/handler_erc20.cairo#L183


# Vulnerability details

## Impact

In the `cross_chain_erc20_settlement()`, users submit their cross-chain transactions to transfer tokens and release them on the destination handler contract. Additionally, `txId` is generated inside of the function. The problem is that this id is derived using different information on different chain breaking compatibility and violating the spec.


## Proof of Concept

Take a look at how txId is generated on the Starknet:

https://github.com/code-423n4/2024-08-chakra/blob/main/cairo/handler/src/handler_erc20.cairo#L183
```
 let tx_id = LegacyHash::hash(get_tx_info().unbox().transaction_hash, self.msg_count.read());

```

Here we use transaction hash and `msg_count` state variable that's increased with each call to the `cross_chain_erc20_settlement()`. On Ethereum, different approach is used:

https://github.com/code-423n4/2024-08-chakra/blob/main/solidity/handler/contracts/ChakraSettlementHandler.sol#L139-149
```
uint256 txid = uint256(
            keccak256(
                abi.encodePacked(
                    chain,
                    to_chain,
                    msg.sender, // from address for settlement to calculate txid
                    address(this), //  from handler for settlement to calculate txid
                    to_handler,
                    nonce_manager[msg.sender]
                )
            )
        );

```

As per docs:

```
Cross-chain transaction IDs are uniquely generated based on the source and destination chain information, sender, handler addresses, and nonce.
```

As you can see, `txId` generation is done correctly on Ethereum and the wrong way on Starknet. This can result in an unexpected behavior violating the spec and affecting offchain services when transferring cross-chain messages.

## Tools Used

Manual review.

## Recommended Mitigation Steps

Change the way `txId` is generated on the Starknet chain.


## Assessed type

Other