Hashgraph Name Protocol Audit Report

Copyright © 2022 by Verilog Solutions. All rights reserved.

August 11, 2022

by Verilog Solutions

This report presents our engineering engagement with the PieFi dev team on their name service protocol based on Hedera – the Hashgraph Name Protocol.

Project NameHashgraph Name Protocol
Repository Linkhttps://github.com/pieFi-platform/hashgraph-name-protocol
Commit Hashe938ca0236ba53f3284ab2a135bbb7437a1af443
Language Solidity
ChainHedera

About Verilog Solutions

Founded by a group of cryptography researchers and smart contract engineers in North America, Verilog Solutions elevates the security standards for Web3 ecosystems by being a full-stack Web3 security firm covering smart contract security, consensus security, and operational security for Web3 projects.

Verilog Solutions team works closely with major ecosystems and Web3 projects and applies a quality above quantity approach with a continuous security model. Verilog Solutions onboards the best and most innovative projects and provides the best-in-class advisory services on security needs, including on-chain and off-chain components.

Table of Contents

Service Scope

Service Stages

Methodology

  • Code Assessment
    • We evaluate the overall quality of the code and comments as well as the architecture of the repository.
    • We help the project dev team improve the overall quality of the repository by providing suggestions on refactorization to follow the best practice of Web3 software engineering.
  • Code Logic Analysis
    • We dive into the data structures and algorithms in the repository and provide suggestions to improve the data structures and algorithms for the lower time and space complexities.
    • We analyze the hierarchy among multiple modules and the relations among the source code files in the repository and provide suggestions to improve the code architecture with better readability, reusability, and extensibility.
  • Access Control Analysis
    • We perform a comprehensive assessment of the special roles of the project, including their authorities and privileges.
    • We provide suggestions regarding the best practice of privilege role management according to the standard operating procedures (SOP).
  • Off-Chain Components Analysis
    • We analyze the off-chain modules that are interacting with the on-chain functionalities and provide suggestions according to the SOP.
    • We conduct a comprehensive investigation for potential risks and hacks that may happen on the off-chain components and provide suggestions for patches.

Audit Scope

Project Summary

hashgraph.name is a distributed, open, and extensible naming system built on the Hedera Hashgraph.

Hashgraph Name Protocol Architecture

Use Case Scenario

Hashgraph Name is an extension of yourself in web3 and around the Hedera ecosystem. Similar to Ethereum’s naming service, you can set your Hashgraph Name as the reverse record for your Hedera wallet address. It ties human-readable names like ‘baird.hbar’ to machine-readable identifiers such as Hedera wallet addresses, other cryptocurrency addresses, content hashes, and metadata.

Findings & Improvement Suggestions

SeverityTotalAcknowledgedResolved
High111
Medium221
Low553
Informational442

High

  1. Function extendExpiry in SLDNode.sol can be called by any person.
    SeverityHigh
    SourceSLDNode.sol#L100;
    StatusResolved in commit 7cd9d48906129942436d9c05e939d89bd59dc0df.
    • Description

      This is the function used to extend the expiration date of a sub-domain. The function now can be called by anyone. Ideally, the function can only be called by the top-domain owner.

    • Exploit Scenario

      The attacker can call the function arbitrarily to make the sub-level domain chaos.

    • Recommendations

      The function should be protected by the onlyTLDOwner modifier.

Medium

  1. The same SLD hash might be added twice.
    SeverityMedium
    SourceTLDNode.sol#L78;
    StatusAcknowledged.
    • Description

      TLD node might add the same SLD hash record more than one time.

      When the top-level domain (TLD) node adds a new second-level domain (SLD) hash record, it first checks if the SLD node is full or not. If it’s full, a new SLD node contract will be created. In this case, when an SLD hash record is being added to the newly created SLD node contract, we have to first check if the SLD hash record to be added has already been there in the old smart contract before adding it to the new one. Since the new SLD node contract does not have SLD hash records of the previous SLD nodes, the same SLD hash record may be added to the newly created SLD node again.

      The same issue may also occur when updating the SLD nodes (i.e., registering the expired SLD) for the reason that there might be multiple SLD records with the same SLD hash.

    • Exploit Scenario
      1. The SLD hash "Alice" exists on the current SLD node;
      1. The current SLD node is already full;
      1. Alice is able to add the same SLD hash "Alice" to the newly created SLD node;
      1. Now, TLD node exists two same "Alice" hash and each can have different settings and subdomains;
      1. The process can be repeated.
    • Recommendations

      Please change the code and check if the SLD hash exists first before adding a new record to the existing SLD node or creating any new SLD node.

    • Results

      Acknowledged.

      Reply from PieFi team:

      This is a known issue. Hedera is different than other chains in that there are restrictions that limit scalability. The name service is designed to scale with large numbers of SLDNodes, so it is not possible for the TLDNode to search all SLDNodes within the gas limit. As this is a known issue, calls to the TLDNode::registerSLD() function will be restricted to only our backend. Our backend will check for SLD existence before registering a new SLD.”
  1. SubdomainNode.addSubdomain() has logic flaws.
    SeverityMedium
    SourceSubdomainNode.sol#L67;
    StatusResolved in commit b3a22e085eac735371064a14e95e972ba721d078.
    • Description

      SubdomainNode.addSubdomain() has a few logic flaws. Some parameters are not used when the subdomain hash already exists and the information of the subdomain cannot be updated if the length of the subdomain hash array reaches the max record limit.

      The function SubdomainNode.addSubdomain() code is as follows:

      function addSubdomain(bytes32 _subdomainHash, string memory _name, address _owner) external onlySLDNode returns(int32) {
        require(subdomainHashes.length < maxRecords, "This contract is full, no more records can be added.");
        if(records[_subdomainHash].owner == address(0)) {
            subdomainHashes.push(_subdomainHash);
            names.push(_name);
            records[_subdomainHash].name = _name;
        }
        records[_subdomainHash].owner = _owner;
        return HederaResponseCodes.SUCCESS;
      }
      
      1. If the _subdomainHash exists in the records mapping, the parameter _name is never used. The subdomain’s name cannot be updated after being created.
      1. The function will revert when the subdomain hash length reaches the max record limit. The information like owner of the existing subdomain cannot be updated.
    • Exploit Scenario
      1. The subdomain hash length reaches the max record limit.
      1. Alice cannot update the subdomain’s owner because the function reverts.
    • Recommendations
      1. Please consider checking if the length of subdomainHashes array exceeds the max record limit or not only when adding a new subdomain.
      1. Please double-check and confirm that the name does not need to be updated.
    • Results

      The 1st issue is that the _name argument is unused in a specific case.

      Reply from PieFi team:

      This is intentional. The subdomain contract was designed to be as lean as possible. The _name parameter here is the text form of the _subdomainHash. If the subdomain already exists, then there is no reason to update the name.”

      The 2nd issue is that there were flaws in the logic of the function. Those flaws have been resolved in commit b3a22e085eac735371064a14e95e972ba721d078.

Low

  1. The second-level domain can only have limited subdomains.
    SeverityLow
    SourceSLDNode.sol#L125;
    StatusAcknowledged.
    • Description

      SLDNode.addSubdomain() will revert if the corresponding subdomain node reaches the max record limit.

      According to the contract code, every second-level domain will only have one subdomain node to maintain the subdomain record. No more subdomain can be added to the second level domain if the amount of subdomains maintained by the subdomain node reaches the max record limit.

    • Exploit Scenario

      N/A

    • Recommendations

      Create a new subdomain node for a second-level domain when a single subdomain node reaches the max record limit.

    • Results

      Acknowledged.

      Reply from PieFi team:

      This is intentional. In our testing, we found that the Subdomain.sol contract can store more than 2000 subdomains before the contract runs out of space. We find this is an acceptable limitation.”
  1. Domain expiry date extension does not check if the SLD hash exists.
    SeverityLow
    SourceSLDNode.sol#L90;
    StatusResolved in commit b3a22e085eac735371064a14e95e972ba721d078.
    • Description

      SLD hash existence is not checked when extending the expiry date.

      SLDNode.extendExpiry() does not check if the SLD hash record exists or not. SLD hash record that does not exist will have an expiry date after calling this function.

    • Exploit Scenario

      N/A

    • Recommendations

      Check if the SLD hash record exists before extending the expiry date.

  1. Using selfdestruct is not recommended.
    SeverityLow
    SourceHNS protocol
    StatusResolved in commit b3a22e085eac735371064a14e95e972ba721d078.
    • Description

      The function selfdestruct is used in multiple contracts. Consider removing the self-destruct functionality unless it is absolutely required

      Using selfdestruct makes the contract a suspicious metamorphic contract and places users under contract re-init risks. Consider removing the self-destruct functionality unless it is absolutely required. If there is a valid use case, it is recommended to implement a multi-sig scheme so that multiple parties must approve the self-destruct action.

    • Exploit Scenario

      The contract is self-destructed and re-initialized as a new contract. In this case, users lose all the data and values stored on the original contract.

    • Recommendations

      Implement a multi-sig scheme so that multiple parties must approve the self-destruct action.

  1. No function to update the SubDomainNode.maxRecords
    SeverityLow
    SourceSubdomainNode.sol#L11;
    StatusAcknowledged.
    • Description

      There is no function that can be used to update the variable SubDomainNode.maxRecords.

    • Exploit Scenario

      N/A

    • Recommendations

      Mark the variable as immutable or add a function to update the variable’s value.

    • Results

      Acknowledged.

      Reply from PieFi team:

      This is intentional. In our testing, we found that the Subdomain.sol contract can store more than 2000 subdomains before the contract runs out of space. We find this is an acceptable limitation.”
  1. Lack of event emission for critical operations.
    SeverityLow
    SourceHashgraph Name Protocol
    StatusResolved in commit b3a22e085eac735371064a14e95e972ba721d078.
    • Description

      Many of the HNS contract functions related to critical operations do not emit necessary events. Events are vital aids in monitoring contracts and detecting suspicious behaviors. Operations that perform critical operations should trigger events so that users and off-chain monitoring tools can account for important state changes.

    • Exploit Scenario

      N/A

    • Recommendations

      Please consider emitting events in functions that perform critical operations.

    • Results

      Resolved in commit b3a22e085eac735371064a14e95e972ba721d078.

      In this commit,SetSLDInfo, ExtendExpiry, UpdateSLD, AddSubdomain ,SetSubdomainInfo, AddSubdomain, TokenTransfer seven events are added.

Informational

  1. No view function to fetch array length
    SeverityInformational
    SourceSLDNode.sol#L10; SubdomainNode.sol#L8, L9;
    StatusAcknowledged.
    • Description

      There is no view function to fetch the length of array SLDNode.serials, SubdomainNode.subdomainHashes, SubdomainNode.name.

    • Exploit Scenario

      N/A

    • Recommendations

      Add a view function to fetch the length of arrays.

    • Results

      Acknowledged.

      Reply from PieFi team:

      We don’t have a use case to be able to query for the array lengths.”
  1. Add view function to get array item by index
    SeverityInformational
    SourceSLDNode.sol; TLDNode.sol; SubdomainNode.sol;
    StatusAcknowledged.
    • Description

      A view function can be added to fetch array items by index.

    • Exploit Scenario

      N/A

    • Recommendations

      Add view functions to get array items by index.

    • Results

      Acknowledged.

      Reply from PieFi team:

      We don’t have a use case to fetch individual items in the arrays. They are mostly used for tracking purposes. We do, however, want to be able to fetch the entire array in the event we want to view all data in the Node.”
  1. Add view functions to retrieve valid SLD nodes
    SeverityInformational
    SourceSLDNode.sol; TLDNode.sol;
    StatusResolved in commit b3a22e085eac735371064a14e95e972ba721d078.
    • Description

      SLD nodes contract still exists in array in TLD node contract after self-destructed. A view function to view all the nodes that are self-destructed can be added.

    • Exploit Scenario

      N/A

    • Recommendations

      A view function to view all the nodes that are self-destructed can be added.

  1. Access control on external view functions
    SeverityInformational
    SourceSLDNode.sol#L50, L54;
    StatusResolved in commit b3a22e085eac735371064a14e95e972ba721d078.
    • Description

      The view functions SLDNode.getMaxRecords() and SLDNode.getNumRecords() will revert if called by non-TLD owner. Access control on public view functions is unnecessary since everything on the blockchain is public and can be accessed by everyone.

    • Exploit Scenario

      N/A

    • Recommendations

      Suggest removing the access control if it is unnecessary.

Access Control Analysis

  • Owner of TLD node manager

    The owner of TLDManager.sol is the deployer of this contract. The ownership cannot be renounced or transferred to others. The owner can:

    • Register new TLD nodes or override any registered TLD nodes;
    • Self-destruct TLDManager.sol.
  • Owner of TLD node

    The owner of TLDNode.sol is the deployer of this contract. The ownership cannot be renounced or transferred to others. The owner can:

    • Register new SLD node records;
    • Register expired SLD node records;
    • Extend the expiry date of an SLD record;
    • Add subdomain;
    • Set subdomain info;
    • Self-destruct TLDNode.sol;
    • Self-destruct SLDNode.sol;
    • Self-destruct SubdomainNode.sol.

Appendix I: Severity Categories

SeverityDescription
HighIssues that are highly exploitable security vulnerabilities. It may cause direct loss of funds / permanent freezing of funds. All high severity issues should be resolved.
MediumIssues that are only exploitable under some conditions or with some privileged access to the system. Users’ yields/rewards/information is at risk. All medium severity issues should be resolved unless there is a clear reason not to.
LowIssues that are low risk. Not fixing those issues will not result in the failure of the system. A fix on low severity issues is recommended but subject to the client's decisions.
InformationalIssues that pose no risk to the system and are related to the security best practices. Not fixing those issues will not result in the failure of the system. A fix on informational issues or adoption of those security best practices-related suggestions is recommended but subject to clients’ decision.

Appendix II: Status Categories

StatusDescription
UnresolvedThe issue is not acknowledged and not resolved.
Partially ResolvedThe issue has been partially resolved.
AcknowledgedThe Finding / Suggestion is acknowledged but not fixed / not implemented.
ResolvedThe issue has been sufficiently resolved.

Disclaimer

Verilog Solutions receives compensation from one or more clients for performing the smart contract and auditing analysis contained in these reports. The report created is solely for Clients and published with their consent. As such, the scope of our audit is limited to a review of code, and only the code we note as being within the scope of our audit detailed in this report. It is important to note that the Solidity code itself presents unique and unquantifiable risks since the Solidity language itself remains under current development and is subject to unknown risks and flaws. Our sole goal is to help reduce the attack vectors and the high level of variance associated with utilizing new and consistently changing technologies. Thus, Verilog Solutions in no way claims any guarantee of security or functionality of the technology we agree to analyze.

In addition, Verilog Solutions reports do not provide any indication of the technologies proprietors, business, business model, or legal compliance. As such, reports do not provide investment advice and should not be used to make decisions about investment or involvement with any particular project. Verilog Solutions has the right to distribute the Report through other means, including via Verilog Solutions publications and other distributions. Verilog Solutions makes the reports available to parties other than the Clients (i.e., “third parties”) – on its website in hopes that it can help the blockchain ecosystem develop technical best practices in this rapidly evolving area of innovation.