Halborn Logo

Merkle Trade EVM - Taurus Labs


Prepared by:

Halborn Logo

HALBORN

Last Updated 06/26/2024

Date of Engagement by: May 8th, 2024 - May 10th, 2024

Summary

100% of all REPORTED Findings have been addressed

All findings

10

Critical

0

High

0

Medium

0

Low

4

Informational

6


1. Introduction

Taurus Labs engaged Halborn to conduct a security assessment on their smart contracts beginning on 05-08-2024 and ending on 05-10-2024. The security assessment was scoped to the smart contracts provided in the https://github.com/tauruslabs/merkle-swapbridge/tree/main/src GitHub repository. Commit hashes and further details can be found in the Scope section of this report.

2. Assessment Summary

Halborn was provided 3 days 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 expert 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 improvements to reduce the likelihood and impact of risks, which were mostly addressed by the Taurus Labs team. The main identified issues were:

    • Operational reliance on external addresses.

    • Token approvals enabled during contract pause.

    • Centralization risk due to privileged access from owner.

3. 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 contracts' solidity code and can quickly identify items that do not follow security best practices. The following phases and associated tools were used throughout the term of the assessment:

    • Research into architecture and purpose.

    • Smart contract manual code review and walk-through.

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

    • Local testing with custom scripts (Foundry).

    • Fork testing against main networks (Foundry).

    • Static analysis of security for scoped contract, and imported functions.

3.1 Out-of-scope

    • External libraries and financial-related attacks.

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

4. 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.

4.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

4.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}

4.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

5. SCOPE

Files and Repository
(a) Repository: merkle-swapbridge
(b) Assessed Commit ID: 28d7e42
(c) Items in scope:
  • src/SwapBridge.sol
Out-of-Scope:
Remediation Commit ID:
Out-of-Scope: New features/implementations after the remediation commit IDs.

6. Assessment Summary & Findings Overview

Critical

0

High

0

Medium

0

Low

4

Informational

6

Security analysisRisk levelRemediation Date
Token approvals enabled during contract pauseLowSolved - 05/10/2024
Missing return value verification after swapsLowRisk Accepted
Centralization risk due to privileged access from OwnerLowRisk Accepted
Single step ownership transfer risks DOS for privileged functionsLowSolved - 05/10/2024
Operational reliance on external addressesInformationalAcknowledged
Incompatibility risk for EVM versions in different chainsInformationalSolved - 05/10/2024
Unlocked pragma compilerInformationalSolved - 05/10/2024
Use of revert strings over custom errors increases gas costsInformationalSolved - 05/10/2024
Missing state variables visibility modifiersInformationalSolved - 05/10/2024
Missing eventsInformationalSolved - 05/10/2024

7. Findings & Tech Details

7.1 Token approvals enabled during contract pause

// Low

Description

The SwapBridge contract inherits from OpenZeppelins's Pausable contract and allows for control of function execution via the whenNotPaused modifier. However, the approveMax() function is not protected by this modifier. Consequently, token approvals can occur even when the contract is in a paused state, while the swapAndSendToAptos() and sendToAptos() functions, which are intended to be called after approval, would not be able to be called, interrupting the swap process.

BVSS
Recommendation

Protect the approveMax() function with the whenNotPaused modifier to prevent the contract from being able to approve tokens while the contract is paused.

Remediation Plan

SOLVED: The Taurus Labs team has addressed the finding in commit b796692 by following the mentioned recommendation.

Remediation Hash
References
SwapBridge.sol#L28-L30

7.2 Missing return value verification after swaps

// Low

Description

In the swapAndSendToAptos() function, the swapTarget address is utilized to execute the swap through OpenZeppelin’s Address library's functionCall() method, which returns a bytes value upon execution. However, the swapAndSendToAptos() function currently lacks verification of this return value from the swapTarget function call. This lack of verification could lead to unanticipated outcomes if the function call returns a value that is expected to be verified.

BVSS
Recommendation

Handle the return value of the function call, especially if it is expected to contain critical data or if there is uncertainty about its content.

Remediation Plan

RISK ACCEPTED: The Taurus Labs team made a business decision to accept the risk of this finding and not alter the contracts, stating:

The target function of the invocation is one of the swap functions defined in the IParaswap interface. Checking the return value isn’t very practical since different swap functions in IParaswap have different return signatures. Also the value itself isn’t very useful for verification purpose and we can whether the swap has been executed correctly, which we verify by comparing the toToken balance and toAmount after the function call.

Remediation Hash
References
SwapBridge.sol#L62

7.3 Centralization risk due to privileged access from Owner

// Low

Description

The SwapBridge contract inherits from OpenZeppelin's Ownable contract and declares the owner at deployment. This owner address is used to perform administrative actions on the contract, such as token withdrawals and pausing/unpausing contract functions.

This centralization of control over the contract may pose is a risk to the protocol, as this architecture may put the assets of users who have engaged with the protocol in a vulnerable position, exposing them to the potential threat of a rug pull. By centralizing control over the stored funds, the contract compromises on decentralization principles and elevates the risk where user assets could be abruptly withdrawn by the owner, leaving users with no recourse.

BVSS
Recommendation

Several remedial strategies can be employed, including but not limited to: implementing role-based access control, creating low-privileged roles to execute daily tasks in the protocol to limit the impact of possible compromise, transitioning control to a Multi-Signature wallet setup, establishing community-driven governance for decision-making on fund management, integrating time locks and/or setting withdrawal limits to prevent abrupt fund depletion.

Remediation Plan

RISK ACCEPTED: The Taurus Labs team made a business decision to accept the risk of this finding and not alter the contracts, stating:

The contract is purposefully non-upgradeable in order to minimize centralization risk; the Owner has no power to affect change in the behavior of the contract, namely swapping and bridging.

References

7.4 Single step ownership transfer risks DOS for privileged functions

// Low

Description

The SwapBridge contract inherits from OpenZeppelin's Ownable contract and allows for single-step ownership transfer via the transferOwnership() function. Regarding this, it is crucial that the address to which ownership is transferred is verified to be active and willing to assume ownership responsibilities. Otherwise, the contract could be locked in a situation where it is no longer possible to make administrative changes to it.

Additionally, in the Ownable contract, the renounceOwnership() function allows to renounce to the owner permission. Renouncing ownership before transferring it would result in the contract having no owner, eliminating the ability to call privileged functions.

BVSS
Recommendation

Consider using OpenZeppelin's Ownable2Step contract over the Ownable contract, or implementing similar two-step ownership transfer logic into the contract.

Additionally, it is recommended that the owner cannot call the renounceOwnership() function without first transferring ownership to another address. In addition, if a multi-signature wallet is used, the call to the renounceOwnership() function should be confirmed by most signers.

Remediation Plan

SOLVED: The Taurus Labs team has addressed the finding in commit b796692 by following the mentioned recommendation.

Remediation Hash

7.5 Operational reliance on external addresses

// Informational

Description

The SwapBridge contract relies heavily on the tokenBridge and swapTarget addresses, which are established at contract initialization, to operate effectively. The tokenBridge address plays a critical role in quoting fees for swaps and facilitating the transfer of tokens to the Aptos chain. Meanwhile, the swapTarget address is core for executing swaps within the swapAndSendToAptos() function.

This reliance on external addresses underscores the necessity of ensuring these addresses are secure and trusted, as they have substantial control over critical functions of the contract.

BVSS
Recommendation

Ensure the integrity and security of these addresses to maintain the contract's functionality and safeguard against potential unexpected vulnerabilities.

Remediation Plan

ACKNOWLEDGED: The Taurus Labs team made a business decision to acknowledge this finding and not alter the contracts, stating:

To minimize the attack surface, we will ensure the users of SwapBridge contract to approve only the minimal allowance required for each instance a user uses the contract. Moreover, the contract shouldn’t hold any surplus token holdings with normal usage (rescue function is there only to rescue any balance that someone might mistakenly send to the contract).

Remediation Hash
References
SwapBridge.sol#L16-L17

7.6 Incompatibility risk for EVM versions in different chains

// Informational

Description

From Solidity versions 0.8.20 through 0.8.24, the default target EVM version is set to Shanghai, which results in the generation of bytecode that includes PUSH0 opcodes. Starting with version 0.8.25, the default EVM version shifts to Cancun, introducing new opcodes for transient storage, TSTORE and TLOAD.

In this aspect, it is crucial to select the appropriate EVM version when it's intended to deploy contracts on networks other than the Ethereum mainnet, such as L2 chains, which may not support these opcodes. Failure to do so could lead to unsuccessful contract deployments or transaction execution issues.

Score
Recommendation

Make sure to specify the target EVM version when using Solidity versions from 0.8.20 and above, especially if deploying to chains that may not support newly introduced opcodes. Additionally, it is crucial to stay informed about the opcode support of different chains to ensure smooth deployment and compatibility.

Remediation Plan

SOLVED: The Taurus Labs team has addressed the finding in commit b796692 by following the mentioned recommendation and setting a specific EVM version for compilation and deployment. Further testing is required to ensure cross-chain compatibility.

Remediation Hash

7.7 Unlocked pragma compiler

// Informational

Description

The current contract in scope has an unlocked compiler ^0.8.21. To ensure stability, it's important that contracts be deployed with the same compiler version and flags used during development and testing. Locking the pragma helps to ensure that contracts do not accidentally get deployed using another pragma. For example, an outdated pragma version might introduce bugs that affect the contract system negatively.

Score
Recommendation

Lock the pragma version to the same version used during development and testing.

Remediation Plan

SOLVED: The Taurus Labs team has addressed the finding in commit b796692 by following the mentioned recommendation.

Remediation Hash
References
SwapBridge.sol#L2

7.8 Use of revert strings over custom errors increases gas costs

// Informational

Description

In Solidity development, replacing hard-coded revert message strings with the Error() syntax is an optimization strategy that can significantly reduce gas costs. Hard-coded strings, stored on the blockchain, increase the size and cost of deploying and executing contracts.

The Error() syntax allows for the definition of reusable, parameterized custom errors, leading to a more efficient use of storage and reduced gas consumption. This approach not only optimizes gas usage during deployment and interaction with the contract but also enhances code maintainability and readability by providing clearer, context-specific error information.

Score
Recommendation

Consider replacing all revert strings with custom errors. For more reference, see here.

Remediation Plan

SOLVED: The Taurus Labs team has addressed the finding in commit b796692 by following the mentioned recommendation.

Remediation Hash
References
SwapBridge.sol#L22
SwapBridge.sol#L65
SwapBridge.sol#L98

7.9 Missing state variables visibility modifiers

// Informational

Description

The state variables declared in the SwapBridge.sol contract are not explicitly declared with any visibility modifiers. By default, the Solidity compiler will assume any state variable declared in the contract as internal.

It is considered best practice to explicitly specify visibility to enhance clarity and prevent ambiguity. Clearly labeling the visibility of all variables and functions will help in maintaining clear and understandable code.

Score
Recommendation

Explicitly define the visibility for each state variable within the contract.

Remediation Plan

SOLVED: The Taurus Labs team has addressed the finding in commit b796692 by following the mentioned recommendation

Remediation Hash
References
SwapBridge.sol#L13-L17

7.10 Missing events

// Informational

Description

In Solidity development, emitting events is a recommended practice when state-changing functions are invoked. Currently, the SwapBridge contract lacks emission of events, besides the ones emitted during calls with third-party dependencies. This absence may hamper effective state tracking in off-chain monitoring systems.

Score
Recommendation

Consider declaring and emitting events in the contract to enhance transparency and facilitate off-chain monitoring.

Remediation Plan

SOLVED: The Taurus Labs team has addressed the finding in commit b796692 by following the mentioned recommendation.

Remediation Hash

8. Automated Testing

Static Analysis Report

Description

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.

The security team assessed all findings identified by the Slither software, however, findings with related to external dependencies are not included in the below results for the sake of report readability.

Output

Taurus Labs - slither1Taurus Labs - slither2

The findings obtained as a result of the Slither scan were reviewed, and not included in the report because they were determined as false positives.

Unit tests and fuzzing

The original repository used the Foundry environment to develop and test the smart contracts against a local fork. All tests were executed successfully. Additionally, these tests were updated locally to generate additional fuzz tests that covered ~50,000 runs per test. These additional tests were run successfully.

Taurus Labs - Unit & fuzz testing

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.