Halborn Logo

coreBTC - CoreDAO


Prepared by:

Halborn Logo

HALBORN

Last Updated 03/28/2024

Date of Engagement by: January 25th, 2024 - February 26th, 2024

Summary

100% of all REPORTED Findings have been addressed

All findings

7

Critical

0

High

0

Medium

1

Low

2

Informational

4


Introduction

The CoreDAO team engaged Halborn to conduct a security assessment on their smart contracts beginning on 01/25/2024 and ending on 02/26/2024. The security assessment was scoped to the smart contracts provided in the GitHub repository. Commit hashes and further details can be found in the Scope section of this report.

Assessment Summary

Halborn was provided 4 weeks for the engagement and assigned 1 full-time security engineer to review the security of the smart contracts in scope. The engineer is a blockchain and smart contract security experts with advanced penetration testing and smart contract hacking skills, and deep knowledge of multiple blockchain protocols.

The purpose of the assessment is to:

  • Identify potential security issues within the smart contracts.

  • Ensure that smart contract functionality operates as intended.

In summary, Halborn identified some security that were successfully addressed by the CoreDAO team.

Test Approach and Methodology

Halborn performed a combination of manual and automated security testing to balance efficiency, timeliness, practicality, and accuracy in regard to the scope of this assessment. While manual testing is recommended to uncover flaws in logic, process, and implementation; automated testing techniques help enhance coverage of the code and can quickly identify items that do not follow the security best practices. The following phases and associated tools were used during the assessment:

  • Research into architecture and purpose.

  • Smart contract manual code review and walkthrough.

  • Graphing out functionality and contract logic/connectivity/functions (solgraph).

  • Manual assessment of use and safety for the critical Solidity variables and functions in scope to identify any arithmetic related vulnerability classes.

  • Manual testing by custom scripts.

  • Static Analysis of security for scoped contract, and imported functions (slither).

  • Testnet deployment (Foundry).


Out-of-scope

  • External libraries and financial-related attacks.

  • New features/implementations after/with the remediation commit IDs.


1. RISK METHODOLOGY

Every vulnerability and issue observed by Halborn is ranked based on two sets of Metrics and a Severity Coefficient. This system is inspired by the industry standard Common Vulnerability Scoring System.
The two Metric sets are: Exploitability and Impact. Exploitability captures the ease and technical means by which vulnerabilities can be exploited and Impact describes the consequences of a successful exploit.
The Severity Coefficients is designed to further refine the accuracy of the ranking with two factors: Reversibility and Scope. These capture the impact of the vulnerability on the environment as well as the number of users and smart contracts affected.
The final score is a value between 0-10 rounded up to 1 decimal place and 10 corresponding to the highest security risk. This provides an objective and accurate rating of the severity of security vulnerabilities in smart contracts.
The system is designed to assist in identifying and prioritizing vulnerabilities based on their level of risk to address the most critical issues in a timely manner.

1.1 EXPLOITABILITY

Attack Origin (AO):
Captures whether the attack requires compromising a specific account.
Attack Cost (AC):
Captures the cost of exploiting the vulnerability incurred by the attacker relative to sending a single transaction on the relevant blockchain. Includes but is not limited to financial and computational cost.
Attack Complexity (AX):
Describes the conditions beyond the attacker’s control that must exist in order to exploit the vulnerability. Includes but is not limited to macro situation, available third-party liquidity and regulatory challenges.
Metrics:
EXPLOITABILIY METRIC (mem_e)METRIC VALUENUMERICAL VALUE
Attack Origin (AO)Arbitrary (AO:A)
Specific (AO:S)
1
0.2
Attack Cost (AC)Low (AC:L)
Medium (AC:M)
High (AC:H)
1
0.67
0.33
Attack Complexity (AX)Low (AX:L)
Medium (AX:M)
High (AX:H)
1
0.67
0.33
Exploitability EE is calculated using the following formula:

E=meE = \prod m_e

1.2 IMPACT

Confidentiality (C):
Measures the impact to the confidentiality of the information resources managed by the contract due to a successfully exploited vulnerability. Confidentiality refers to limiting access to authorized users only.
Integrity (I):
Measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of data stored and/or processed on-chain. Integrity impact directly affecting Deposit or Yield records is excluded.
Availability (A):
Measures the impact to the availability of the impacted component resulting from a successfully exploited vulnerability. This metric refers to smart contract features and functionality, not state. Availability impact directly affecting Deposit or Yield is excluded.
Deposit (D):
Measures the impact to the deposits made to the contract by either users or owners.
Yield (Y):
Measures the impact to the yield generated by the contract for either users or owners.
Metrics:
IMPACT METRIC (mIm_I)METRIC VALUENUMERICAL VALUE
Confidentiality (C)None (I:N)
Low (I:L)
Medium (I:M)
High (I:H)
Critical (I:C)
0
0.25
0.5
0.75
1
Integrity (I)None (I:N)
Low (I:L)
Medium (I:M)
High (I:H)
Critical (I:C)
0
0.25
0.5
0.75
1
Availability (A)None (A:N)
Low (A:L)
Medium (A:M)
High (A:H)
Critical (A:C)
0
0.25
0.5
0.75
1
Deposit (D)None (D:N)
Low (D:L)
Medium (D:M)
High (D:H)
Critical (D:C)
0
0.25
0.5
0.75
1
Yield (Y)None (Y:N)
Low (Y:L)
Medium (Y:M)
High (Y:H)
Critical (Y:C)
0
0.25
0.5
0.75
1
Impact II is calculated using the following formula:

I=max(mI)+mImax(mI)4I = max(m_I) + \frac{\sum{m_I} - max(m_I)}{4}

1.3 SEVERITY COEFFICIENT

Reversibility (R):
Describes the share of the exploited vulnerability effects that can be reversed. For upgradeable contracts, assume the contract private key is available.
Scope (S):
Captures whether a vulnerability in one vulnerable contract impacts resources in other contracts.
Metrics:
SEVERITY COEFFICIENT (CC)COEFFICIENT VALUENUMERICAL VALUE
Reversibility (rr)None (R:N)
Partial (R:P)
Full (R:F)
1
0.5
0.25
Scope (ss)Changed (S:C)
Unchanged (S:U)
1.25
1
Severity Coefficient CC is obtained by the following product:

C=rsC = rs

The Vulnerability Severity Score SS is obtained by:

S=min(10,EIC10)S = min(10, EIC * 10)

The score is rounded up to 1 decimal places.
SeverityScore Value Range
Critical9 - 10
High7 - 8.9
Medium4.5 - 6.9
Low2 - 4.4
Informational0 - 1.9

2. SCOPE

Files and Repository
(a) Repository: btcwrap-contracts
(b) Assessed Commit ID: 86a3b4f
(c) Items in scope:
  • ./routers/BurnRouterStorage.sol
  • ./routers/CcTransferRouterStorage.sol
  • ./routers/BurnRouterLogic.sol
↓ Expand ↓
Out-of-Scope: Third-party libraries and dependencies, Economic attacks, Test and mock contacts
Remediation Commit ID:
Out-of-Scope: New features/implementations after the remediation commit IDs.

3. Assessment Summary & Findings Overview

Critical

0

High

0

Medium

1

Low

2

Informational

4

Security analysisRisk levelRemediation Date
Incompatibility with Multi-Signature Wallets Due to .transfer UsageMediumSolved - 03/01/2024
Missing init functions on the upgradeable contractsLowSolved - 03/01/2024
Implementations Can Be InitializedLowSolved - 03/01/2024
Redundant "Instant Router" Variable Not Utilized in ContractInformationalSolved - 03/01/2024
Finalization Parameter Not Configurable in Contract InitializationInformationalSolved - 03/01/2024
Unsafe ERC20 operation(s)InformationalAcknowledged - 03/01/2024
Inconsistent Initialization of Ownable in BitcoinRelayLogic ContractInformationalSolved - 03/01/2024

4. Findings & Tech Details

4.1 Incompatibility with Multi-Signature Wallets Due to .transfer Usage

// Medium

Description

The smart contract functions slashIdleLocker, slashThiefLocker, and liquidateLocker use Solidity's .transfer method to send Ether (or native tokens) to recipients. While .transfer is designed to prevent reentrancy attacks by limiting the gas sent to 2300, it poses significant limitations, particularly when interacting with contracts that require more gas to execute their fallback functions, such as multi-signature wallets. This limitation prevents multi-signature wallets from being used as recipients in these transactions, as they typically require more gas to accept and process incoming transfers.


    function slashIdleLocker(
        address _lockerTargetAddress,
        uint _rewardAmount,
        address _rewardRecipient,
        uint _amount,
        address _recipient
    ) external override nonReentrant whenNotPaused returns (bool) {
        require(
            _msgSender() == ccBurnRouter,
            "Lockers: message sender is not ccBurn"
        );

        uint equivalentNativeToken = LockersLib.slashIdleLocker(
            lockersMapping[_lockerTargetAddress],
            libConstants,
            libParams,
            _rewardAmount,
            _amount
        );

        // Transfers TNT to user
        payable(_recipient).transfer(equivalentNativeToken*_amount/(_amount + _rewardAmount));
        // Transfers TNT to slasher
        uint rewardAmountInNativeToken = equivalentNativeToken - (equivalentNativeToken*_amount/(_amount + _rewardAmount));
        payable(_rewardRecipient).transfer(rewardAmountInNativeToken);

        emit LockerSlashed(
            _lockerTargetAddress,
            rewardAmountInNativeToken,
            _rewardRecipient,
            _amount,
            _recipient,
            equivalentNativeToken,
            block.timestamp,
            true
        );

        return true;
    }
BVSS
Recommendation

Replace the .transfer method with Address.sendValue, a function provided by OpenZeppelin's Address utility library. sendValue safely sends Ether while providing all available gas (minus a stipend for the transaction itself), thus accommodating contracts that consume more gas in their fallback functions.


Remediation Plan

SOLVED : The CoreDAO team solved the issue by using sendValue function.

Remediation Hash

4.2 Missing init functions on the upgradeable contracts

// Low

Description

The contracts, which are designed to be upgradeable using the UUPS pattern, seem to be missing proper initialization functions. The initial setup for a UUPS upgradeable contract is crucial to ensure that the contract can be safely upgraded in the future without losing state or introducing vulnerabilities.


Code Location : https://github.com/coredao-org/btcwrap-contracts/blob/86a3b4f2d0569e1bd520a88356c31076a584ec8d/contracts/common/relay/BitcoinRelayLogic.sol#L11

BVSS
Recommendation

To address this concern, ensure that all base contracts are properly initialized in the initialize function.


Remediation Plan

SOLVED : The CoreDAO team solved the issue by calling the init function.

Remediation Hash

4.3 Implementations Can Be Initialized

// Low

Description

The contracts are upgradable, inheriting from the Initializable contract. However, the current implementations are missing the _disableInitializers() function call in the constructors. Thus, an attacker can initialize the implementation. Usually, the initialized implementation has no direct impact on the proxy itself; however, it can be exploited in a phishing attack. In rare cases, the implementation might be mutable and may have an impact on the proxy.

BVSS
Recommendation

It is recommended to call [_disableInitializers](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/Initializable.sol#L145) within the contract's constructor to prevent the implementation from being initialized.


Remediation Plan

SOLVED : The CoreDAO team solved the issue by using disableInitializers.

Remediation Hash

4.4 Redundant "Instant Router" Variable Not Utilized in Contract

// Informational

Description

Within the CcTransferRouterLogic contract, an "instant router" variable setter (setInstantRouter) is defined but appears to be redundant, as there is no subsequent utilization or reference to the "instant router" variable within the contract logic. This redundancy not only bloats the contract code but also introduces potential confusion regarding the contract's intended functionality and architecture.

The presence of unused variables and functions can obscure the contract's intended logic and make the codebase harder to maintain and understand.

Code Location : https://github.com/coredao-org/btcwrap-contracts/blob/main/contracts/routers/CcTransferRouterLogic.sol#L99


    /// @notice                             Setter for instant router
    /// @dev                                Only owner can call this
    /// @param _instantRouter               Address of the instant router contract
    function setInstantRouter(address _instantRouter) external override nonZeroAddress(_instantRouter) onlyOwner {
        _setInstantRouter(_instantRouter);
    }
Score
Recommendation

Conduct a thorough review of the contract code to identify and remove unused variables, functions, and logic paths. Specifically, evaluate the necessity of the "instant router" variable and its associated setter function. If confirmed as redundant, remove the setInstantRouter function and any related code.


Remediation Plan

SOLVED : The CoreDAO team solved the issue by deleting redundant function/variable.

Remediation Hash

4.5 Finalization Parameter Not Configurable in Contract Initialization

// Informational

Description

The BitcoinRelayLogic contract includes functionality to set the finalizationParameter, which determines the number of confirmations required for a transaction to be considered finalized. While a setter function exists for adjusting this parameter post-deployment, the initial value of the finalizationParameter is hardcoded to 3 during contract initialization. This design limits the contract's flexibility and adaptability at deployment, as it does not allow for the initial configuration of the finalization parameter.

Score
Recommendation

Modify the initialize function to accept the finalizationParameter as an input argument. This adjustment will enable the contract deployer to set an appropriate initial value for the finalization parameter based on specific needs and conditions.


Remediation Plan

SOLVED : The CoreDAO team solved the issue by setting a parameter on the constructor.

Remediation Hash

4.6 Unsafe ERC20 operation(s)

// Informational

Description

Currently, the contracts do not adequately handle atypical ERC20 tokens on the staking. According to the ERC20 specification, tokens should return "false" when a transfer fails, but it does not guarantee that the function will revert. This discrepancy could potentially lead to silent failures, making it difficult to detect issues when they occur.

For instance, from the below, It can be seen that [LDO](https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code) does not revert If the user balance is not enough for the transfer.

Note : Even if It does not pose risk for CoreBTC, It is recommended to use safeApprove & safeTransfer/safeTransferFrom.

Score
Recommendation

Consider using safeApprove - safeTransfer - safeTransferFrom from Openzeppelin.


Remediation Plan

ACKNOWLEDGED : The CoreDAO team acknowledged the issue.

4.7 Inconsistent Initialization of Ownable in BitcoinRelayLogic Contract

// Informational

Description

The BitcoinRelayLogic contract, which implements Ownable2StepUpgradeable among other functionalities, incorrectly uses OwnableUpgradeable.__Ownable_init() for initialization instead of the expected Ownable2StepUpgradeable.__Ownable2Step_init().


    /// @notice Gives a starting point for the relay
    /// @param  _height The starting height
    /// @param  _btcLightClient BTC light cient address
    function initialize(
        uint256 _height,
        address _btcLightClient
    ) public initializer {

        OwnableUpgradeable.__Ownable_init();
        ReentrancyGuardUpgradeable.__ReentrancyGuard_init();
        PausableUpgradeable.__Pausable_init();

        // Relay parameters
        btcLightClient = _btcLightClient;

        _setFinalizationParameter(3);
        initialHeight = _height;
    }
Score
Recommendation

Update the initialize function within the BitcoinRelayLogic contract to use the correct initialization method for Ownable2StepUpgradeable. Replace OwnableUpgradeable.__Ownable_init() with Ownable2StepUpgradeable.__Ownable2Step_init() to ensure that all intended functionalities and security enhancements are correctly initialized and available.


Remediation Plan

SOLVED : The CoreDAO team solved the issue by calling Ownable2Step_init()function.

Remediation Hash

5. Automated Testing

Introduction

Halborn used automated testing techniques to enhance the coverage of certain areas of the smart contracts in scope. Among the tools used was Slither, a Solidity static analysis framework. After Halborn verified the smart contracts in the repository and was able to compile them correctly into their abis and binary format, Slither was run against the contracts. This tool can statically verify mathematical relationships between Solidity variables to detect invalid or inconsistent usage of the contracts' APIs across the entire code-base.

All issues identified by Slither were proved to be false positives or have been added to the issue list in this report.



Halborn strongly recommends conducting a follow-up assessment of the project either within six months or immediately following any material changes to the codebase, whichever comes first. This approach is crucial for maintaining the project’s integrity and addressing potential vulnerabilities introduced by code modifications.

© Halborn 2024. All rights reserved.