Assessment reports>Circuit DAO>Critical findings>Missing ,MOD_HASH, validation
Category: Business Logic

Missing MOD_HASH validation

Critical Severity
Critical Impact
High Likelihood

Description

The communication between two puzzles take place via the SEND_MESSAGE and RECEIVE_MESSAGE conditions. The third parameter of the condition SEND_MESSAGE is the destination, and for the RECEIVE_MESSAGE, it is the source from which the message originated. The source of the messages in the puzzles are calculated via calculating the tree hash of the mod of the source puzzle along with the parameters. While the source mod hash is usually either curried in the destination mod itself or verified via the statutes announcements, the parameter (args) hash is provided as the solution of the destination puzzle. The args of the destination could therefore be set to any value as long as the source of the message is correctly asserted. In the source puzzle, if we curry incorrect values, it should be prevented via the lineage as it makes sure that the coin to be spent has the parent coin of the same type.

Taking an example of governance and the statutes-mutation interaction, the RECEIVE_MESSAGE in statutes mutation verifies that the message was sent via the following puzzle hash:

governance_puzzle_hash (tree_hash_of_apply GOVERNANCE_MOD_HASH governance_curried_args_hash)

Although the value of governance_curried_args_hash could be controlled by the attacker, the only problem is that these values cannot be arbitrarily set, as the governance mod verifies the lineage via the following code:

(list ASSERT_MY_PARENT_ID
  (calculate-coin-id
    parent_parent_id
    (curry_hashes CAT_MOD_HASH
      (sha256 ONE CAT_MOD_HASH)
      (sha256 ONE CRT_TAIL_HASH)
      (curry_hashes MOD_HASH
        (sha256 ONE MOD_HASH)
        (sha256 ONE CAT_MOD_HASH)
        (sha256 ONE CRT_TAIL_HASH)
        (sha256tree STATUTES_STRUCT)
        (sha256 ONE INNER_PUZZLE_HASH)
        prev_bill_hash
      )
    )
    amount
  )
)

This ensures that the parent of the current coin is the governance coin — only if the MOD_HASH is set to the governance_mod_hash. The issue arises if this coin is created via a CRT CAT coin with the mod hash controlled by the attacker. This way, they could launch a new coin with the puzzle hash of the governance_mod_hash, but the MOD_HASH value should be that of the previous coin along with the BILL already curried inside the coin. This makes it possible to prove the lineage along with the BILL arguments to be set to any values, and thus the attacker could enact the bill in the next transaction as they control the governance_curried_args_hash passed to the statutes_mutation puzzle.

Impact

The vulnerability allows to incorrectly prove lineage of certain coins and send messages to other puzzles, which could be received via passing the incorrect arg hashes. Sending malicious messages could lead to various issues, including changing global variables without governance voting, potentially winning recharge auctions without bidding, and so forth.

Recommendations

While discussing the issue with the Voltage Technologies Ltd. team, we concluded that asserting the puzzle hash of the puzzle during spending should be able to resolve the issue as it makes sure that the mod hash of the puzzle and MOD_HASH curried inside are correct.

Remediation

This issue has been acknowledged by Voltage Technologies Ltd., and fixes were implemented in the following commits:

Zellic © 2025Back to top ↑