• Hacken
  • Blog
  • Case Studies
  • Blockchain Protocol Audit For Substrate-Built Analog

Blockchain Protocol Audit For Substrate-Built Analog

8 minutes

By Malanii Oleh

Introduction

Analog is a suite of interoperability protocols built on the Substrate SDK, designed to be a comprehensive solution for multi-chain and cross-chain development. In March 2024, Hacken completed a comprehensive Blockchain Protocol Audit of Analog’s Node, SDK, and Chain. 

In this post, we aim to highlight the most interesting vulnerabilities, how they were discovered, their potential consequences, and the steps taken to mitigate them. For more information, see the full audit report.

About Analog

Analog is the foundational, sovereign blockchain based on a Nominated Proof-of-Stake (NPoS). It is designed to address the challenges of cross-chain and multi-chain interactions in Web3, enabling developers and users to seamlessly leverage the benefits of any blockchain.

Key Features of Analog

  • Timechain: A Rust-based blockchain hosting validators called Time Nodes and Chronicle Nodes that validate and relay messages.
  • Analog Watch: A full-stack indexing and query protocol that makes Web3 data instantly and securely accessible over a GraphQL endpoint. 
  • Analog GMP: A permissionless on-chain utility powered by the Timechain that enables messages to flow freely and securely across blockchains.
  • Cross-Chain Automation Product: Enables cross-chain smart contract executions.

Substrate Project With TSS Implementation

Overall, this is a Substrate project, with the scope consisting of Substrate pallets and additional node functionality in a separate crate. The pallets implement the core logic of the Timechain. The more complex part was the logic outside the pallets, as they implemented TSS (Threshold Signature Scheme) in their node.

Audit Overview

In March 2024, Hacken completed a comprehensive Blockchain Protocol Audit of Analog’s Node, SDK, and Chain. The audit, which lasted a few months, focused on various aspects, including the system’s code quality, architecture quality, documentation, and overall security. 

We have identified a total of 15 issues, categorized by severity:

  • Critical Issues: 0
  • High Issues: 1
  • Medium Issues: 1
  • Low Issues: 13

All the issues were fixed, granting a maximum security score within the audited scope.

The audit report has been made public by Analog, in this post, we want to uncover the most interesting vulnerabilities, how they were discovered, what consequences, and mitigated. 

High-Severity Vulnerability – Replay Attack and DoS

The only high-severity issue was a vulnerability inside Runtime & Pallets that allowed the replay or DoS attack. Let’s review this vulnerability and the implemented fix in detail.

The submit_error extrinsic within the tasks pallet presented a significant security risk. This vulnerability originated from the absence of validation against the resubmission of identical error signatures. As a result, it opened up the potential for a replay attack, in which malicious actors repeatedly submit the same error signature. This repetitive submission undermined the system’s integrity and triggered a Denial of Service (DoS) by prematurely forcing tasks into a failure state.

Replay Attack

Pre-audit, the signature verification process, did not utilize a nonce or any other method to guarantee the uniqueness of each submission. This absence of a uniqueness check allowed the same signature to be used repeatedly without being invalidated after its first use, as shown in the following code:

/// Submit Task Error

#[pallet::call_index(4)]

#[pallet::weight(T::WeightInfo::submit_error())]

pub fn submit_error(

origin: OriginFor<T>,

    task_id: TaskId,

    cycle: TaskCycle,

    error: TaskError,

) -> DispatchResult {

ensure_signed(origin)?;

    ensure!(Tasks::<T>::get(task_id).is_some(), Error::<T>::UnknownTask);

    Self::validate_signature(

     task_id,

        cycle,

        error.shard_id,

        schnorr_evm::VerifyingKey::message_hash(error.msg.as_bytes()),

        error.signature,

    )?;

// ...

In the implementation, the signature is created based on public parameters such as the task ID, task cycle, error shard ID, and the error message, all visible when the extrinsic is called. Yet, this process does not incorporate a nonce or any other unique identifier to ensure the uniqueness of each transaction.

The absence of a nonce in the signature generation means that the signature remains valid for multiple transactions as long as the public parameters remain the same. In a blockchain environment, where transaction details are publicly visible on the chain, this aspect of transparency becomes a double-edged sword. While it upholds the blockchain’s principle of openness, it also means that any user can view the details of transactions, including those that call the submit_error extrinsic.

Denial of Service

As previously described, a malicious actor could exploit the replay attack vulnerability to repeatedly submit the same submit_error extrinsic with a valid signature.

Each successful execution of the submit_error extrinsic increments the TaskRetryCounter for the specified task. This counter tracks the number of times an error has been submitted for a task.

In the runtime configuration, type MaxRetryCount = ConstU8<3> specifies that the maximum retry count for a task was set to 3. This is a critical threshold value in the context of task execution.
When the TaskRetryCounter reaches the maximum retry count of 3, as defined in the runtime configuration, the task’s state is automatically set to Failed. This is enforced by the line TaskState::<T>::insert(task_id, TaskStatus::Failed { error: error.clone() }); in the submit_error extrinsic.

Once the retry counter hits this limit, the task is marked as failed regardless of the actual validity or severity of the reported errors.

Potential Consequences

If this vulnerability had gone unnoticed, several potential consequences could have occurred:

  • Premature Task Failure: A malicious actor can cause a task to fail prematurely by artificially inflating the retry count. This is achieved by repeatedly submitting the same error signature until the retry count threshold is reached.
  • Disruption of Normal Operations: A premature task failure can disrupt the normal operations of the blockchain system, leading to a denial of service for those particular tasks.
  • Undermining System Reliability: Repeated occurrences of such incidents can erode trust in the system’s reliability, as legitimate tasks may be unjustly terminated due to this vulnerability.

Remediation

To address the DoS vulnerability in the submit_error extrinsic, Hacken auditors recommended incorporating the TaskRetryCounter as part of the signature. This approach effectively uses the TaskRetryCounter as a nonce, adding a unique element to each transaction and thereby mitigating the risk of replay attacks. Here’s a detailed recommendation:

Incorporate TaskRetryCounter into Signature:

  • Unique Transaction Identifier: Modify the signature generation process to include the current value of the TaskRetryCounter for the task. Each time an error is reported and the submit_error extrinsic is called, the TaskRetryCounter is incremented. By including this incremented value in the signature, each submission becomes unique.
  • Preventing Replay Attacks: This change ensures that a signature used in a previous submission cannot be reused for a new submission, as the TaskRetryCounter part of the signature would differ. This effectively prevents the possibility of replaying the same transaction.

Low Severity Issue – Validation Gap for Pending Nodes in ROAST Protocol

The identified issue stems from the ROAST implementation in the tss crate, specifically the coordinator’s failure to verify that a node submitting a commitment is not concurrently in a pending state within an existing signing session. This lack of verification contradicts the fundamental logic of ROAST.

The root cause lies in the implementation of the on_commit function for RoastCoordinator, as depicted below:

fn on_commit(&mut self, peer: Identifier, commitment: SigningCommitments) {

    self.commitments.insert(peer, commitment);

}

Upon receiving a ROAST request containing a commitment, the coordinator directly appends it to the map storing commitments for future sessions, neglecting to confirm whether the signer is currently involved in any ongoing signing session. As the coordinator proceeds to initiate a new session upon accumulating a sufficient number of commitments, the existing flaw permits a node already pending in one signing session to commit once again and engage in other sessions.

This deviation from the fundamental logic of the ROAST protocol is critical, as the protocol’s robustness relies on the premise that each signer is pending in at most one session. The protocol anticipates a finite and limited number of sessions to conclude. However, the identified flaw introduces a vulnerability, enabling a malicious node to secure a position in every session by consistently dispatching commitments to the coordinator. Subsequently, the malicious node can impede session termination by withholding its signature share.

This compromised scenario severely undermines the robustness of the ROAST protocol, providing an avenue for any malicious member to obstruct the process and obstruct the computation of a valid signature.

Potential Consequences

It is essential to underscore that the current risk level is relatively low, contingent upon the centralized nature of the chronicles, where all shard members are presumed non-malicious. However, as the project transitions to a decentralized model, this issue becomes more critical, representing a vulnerability susceptible to exploitation by any shard member. Such exploitation could compromise the performance and overall security of the system.

Other Issues

A variety of medium and low severity issues were identified, ranging from logical inconsistencies in the use of non-cryptographically secure crates to a lack of phase validation in task execution. All issues were addressed with specific recommendations, including:

  • Utilizing Substrate’s Randomness Trait: For secure random number generation.
  • Implementing Task State Validation: To ensure operations are only performed on active tasks.
  • Encrypting Chronicle’s Secret Share: To prevent unauthorized access and misuse.

Impact on Analog

Analog has resolved all the identified issues and implemented recommendations, enhancing its security posture as an innovative solution for omni-chain interoperability. We strongly believe that an audit by a credible and knowledgeable third party will enhance stakeholder confidence in Analog’s security measures and readiness for broader adoption in the Web3 ecosystem.

Analog’s proactive approach to addressing audit findings demonstrates its commitment to maintaining high-security standards and fostering a trustworthy environment for cross-chain application developers. The comprehensive audit by Hacken has thus played a crucial role in refining Analog’s security posture and ensuring its resilience against potential vulnerabilities.

Conclusion

Hacken’s audit of Analog revealed a well-architected and innovative system with high code quality and robust security measures. All of the identified issues were addressed by the Analog team. This audit not only strengthened the security of Analog’s platform but also highlighted areas for continuous improvement, ensuring the project’s long-term success and reliability.

Subscribe
to our newsletter

Be the first to receive our latest company updates, Web3 security insights, and exclusive content curated for the blockchain enthusiasts.

Speaker Img

Table of contents

Tell us about your project

Follow Us

Read next:

More related
  • Blog image
    Decoded: KyberSwap Hack vs Extractor Prevention Mechanisms

    9 min read

    Case Studies

  • Blog image
  • Blog image
More related →

Trusted Web3 Security Partner