Prepared by:
HALBORN
Last Updated 04/17/2024
Date of Engagement by: March 11th, 2024 - March 22nd, 2024
100% of all REPORTED Findings have been addressed
All findings
5
Critical
0
High
0
Medium
1
Low
0
Informational
4
The CoreDAO Team
engaged Halborn to conduct a security assessment on their smart contracts beginning on 03/11/2024 and ending on 03/22/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.
Halborn was provided 2 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 mostly addressed by the CoreDAO team.
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
).
External libraries and financial-related attacks.
New features/implementations after/with the remediation commit IDs.
EXPLOITABILIY METRIC () | METRIC VALUE | NUMERICAL 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 |
IMPACT METRIC () | METRIC VALUE | NUMERICAL 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 |
SEVERITY COEFFICIENT () | COEFFICIENT VALUE | NUMERICAL VALUE |
---|---|---|
Reversibility () | None (R:N) Partial (R:P) Full (R:F) | 1 0.5 0.25 |
Scope () | Changed (S:C) Unchanged (S:U) | 1.25 1 |
Severity | Score Value Range |
---|---|
Critical | 9 - 10 |
High | 7 - 8.9 |
Medium | 4.5 - 6.9 |
Low | 2 - 4.4 |
Informational | 0 - 1.9 |
Critical
0
High
0
Medium
1
Low
0
Informational
4
Security analysis | Risk level | Remediation Date |
---|---|---|
Front-Running in delegateBtc Function | Medium | Solved - 03/22/2024 |
Lack of Dynamic Governance Control Over CLAIM_ROUND_LIMIT in PledgeAgent Contract | Informational | Acknowledged |
Missing Implementations in the IPledgeAgent Interface for BTC Delegation and Reward Distribution | Informational | Solved - 03/22/2024 |
Typo in BtcExpireInfo Struct Mapping Name | Informational | Solved - 03/24/2024 |
Lack of Reentrancy Protection in Public Functions transferBtc and claimBtcReward | Informational | Acknowledged |
// Medium
The delegateBtc
function, intended for users to delegate Bitcoin (BTC) to the Core blockchain, lacks mechanisms to prevent front-running attacks. This vulnerability arises from the function's design, which does not account for the potential for malicious actors to observe and preempt legitimate transactions in the mempool, potentially affecting the intended transaction outcomes. A successful front-running attack against this function could lead to unauthorized entities intercepting or duplicating the delegation of BTC, effectively siphoning off fees intended for the rightful transaction sender.
function delegateBtc(bytes calldata btcTx, uint32 blockHeight, bytes32[] memory nodes, uint256 index, bytes memory script) external {
require(script[0] == bytes1(uint8(0x04)) && script[5] == bytes1(uint8(0xb1)), "not a valid redeem script");
bytes32 txid = btcTx.calculateTxId();
require(ILightClient(LIGHT_CLIENT_ADDR).
checkTxProof(txid, blockHeight, (btcConfirmBlock == 0 ? INIT_BTC_CONFIRM_BLOCK : btcConfirmBlock), nodes, index), "btc tx not confirmed");
BtcReceipt storage br = btcReceiptMap[txid];
require(br.value == 0, "btc tx confirmed");
uint32 lockTime = parseLockTime(script);
br.endRound = lockTime / ROUND_INTERVAL;
require(br.endRound > roundTag + (minBtcLockRound == 0 ? INIT_MIN_BTC_LOCK_ROUND : minBtcLockRound), "insufficient lock round");
(,,bytes29 voutView,) = btcTx.extractTx();
bytes29 payload;
uint256 outputIndex;
(br.value, payload, outputIndex) = voutView.parseToScriptValueAndData(script);
require(br.value > (minBtcValue == 0 ? INIT_MIN_BTC_VALUE : minBtcValue), "staked value does not meet requirement");
uint256 fee;
(br.delegator, br.agent, fee) = parseAndCheckPayload(payload);
if (!ICandidateHub(CANDIDATE_HUB_ADDR).isCandidateByOperate(br.agent)) {
revert InactiveAgent(br.agent);
}
emit delegatedBtc(txid, br.agent, br.delegator, script, blockHeight, outputIndex);
if (fee != 0) {
br.fee = fee;
br.feeReceiver = payable(msg.sender);
}
Agent storage a = agentsMap[br.agent];
br.rewardIndex = a.rewardSet.length;
addExpire(br);
a.totalBtc += br.value;
}
Observation: An attacker continuously monitors the mempool for transactions calling the delegateBtc
function.
Construction: Upon identifying a legitimate transaction intended for delegation, the attacker constructs a similar transaction. This transaction duplicates the parameters of the original (btcTx
, blockHeight
, nodes
, index
, and script
) but includes a higher gas price to ensure it is mined before the legitimate transaction.
Execution: The attacker submits their transaction to the network. Given the higher gas price, miners prioritize this transaction over the original.
Outcome: The attacker's transaction is processed first, potentially resulting in the redirection of fees or the invalidation of the legitimate user's transaction due to nonce or state conflicts.
Ensure that the contract state checks the uniqueness of each identifier and rejects transactions with identifiers that have already been used.
SOLVED : The CoreDAO team solved the issue by adding the initial delegate BTC price.
// Informational
The PledgeAgent
contract, a component of our blockchain system designed for handling reward claims, employs a hardcoded constant, CLAIM_ROUND_LIMIT
, to define the maximum number of rounds for which rewards can be claimed in a single transaction. This parameter plays a critical role in managing gas consumption during these transactions, ensuring that operations remain efficient and do not exceed gas limits. However, the current implementation's rigidity, resulting from the CLAIM_ROUND_LIMIT
being a constant value, limits the system's adaptability to evolving network conditions or governance policies. As network congestion, gas prices, and operational parameters change, the inability to adjust this limit dynamically could lead to inefficiencies or hindered functionality for users attempting to claim rewards.
uint32 public constant INIT_BTC_CONFIRM_BLOCK = 3;
uint256 public constant INIT_MIN_BTC_LOCK_ROUND = 7;
uint256 public constant ROUND_INTERVAL = 86400;
uint256 public constant INIT_MIN_BTC_VALUE = 1e6;
uint256 public constant INIT_BTC_FACTOR = 5e4;
uint256 public constant BTC_STAKE_MAGIC = 0x5341542b;
uint256 public constant CHAINID = 1116;
uint256 public constant FEE_FACTOR = 1e18;
int256 public constant CLAIM_ROUND_LIMIT = 500;
uint256 public constant BTC_UNIT_CONVERSION = 1e10;
Instead of a hardcoded constant, make CLAIM_ROUND_LIMIT
a variable that can be adjusted through governance actions.
ACKNOWLEDGED : The CoreDAO team acknowledged the issue.
// Informational
The IPledgeAgent smart contract provides a framework for delegating Bitcoin (BTC) to the Core network, facilitating staking, reward claims, and the transfer of staked BTC among validators. The contract includes functions for parsing transaction data, validating Bitcoin transaction proofs, managing staking receipts, and distributing rewards. However, the IPledgeAgent interface does not reflect all the functionalities implemented in the contract, particularly the newer functions related to BTC delegation.
interface IPledgeAgent {
function addRoundReward(address[] calldata agentList, uint256[] calldata rewardList) payable external;
function getHybridScore(address[] calldata candidates, uint256[] calldata powers, uint256 round) external returns(uint256[] memory);
function setNewRound(address[] calldata validatorList, uint256 round) external;
function distributePowerReward(address candidate, address[] calldata miners) external;
function onFelony(address agent) external;
}
Consider implementing missing interface definitions.
SOLVED : The CoreDAO team solved the issue by adding missing interfaces.
// Informational
Within the PledgeAgent
contract, specifically in the BtcExpireInfo
struct, there is a typographical error in the naming of one of its mappings: agentExsitMap
.
Update all instances of agentExsitMap
to agentExistMap
within the contract.
SOLVED : The CoreDAO team solved the issue by fixing the typo.
// Informational
The transferBtc
and claimBtcReward
functions in the provided contract are public functions that involve the transfer of Ether (rewards) to external addresses. However, these functions do not implement any reentrancy protection mechanisms. In the case of transferBtc
, the function calls collectBtcReward
, which in turn calls distributeReward
. The distributeReward
function uses the low-level send
function to transfer Ether (rewards) to the delegator's address. Although, the send
/ transfer
function provides some protection against reentrancy by limiting the gas forwarded to the recipient's fallback function.
Even if It does not pose risk directly, Consider implementing re-entrancy protection on the functions.
ACKNOWLEDGED : The CoreDAO team acknowledged the issue.
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.
// Download the full report
* Use Google Chrome for best results
** Check "Background Graphics" in the print settings if needed