Summary
Two security bugs in Heimdall’s ABCI layer were reported and confirmed via the Bug Bounty Program. Under specific conditions, these bugs could have allowed a malicious validator to trigger a Denial of Service (DoS) and cause a chain halt.
Both issues have been fixed and a patched release is available.
Root Cause
Issue 1 – Non-deterministic majority selection & vote inflation
The first issue was in the GetMajorityMilestoneProposition function in the ABCI layer.
-
Vote inflation via repeated keys
The function maintains a
parentHashToVotingPowermap.The key for this map was derived directly from the proposition data, which meant the same key could be inserted multiple times during a single iteration.
A faulty validator could exploit this by:
-
Reusing the same parent hash key multiple times with different data,
-
Artificially inflating the voting power for that parent hash,
-
While still being able to vote for different proposition data.
-
-
Non-determinism due to map iteration
The function then iterated over
parentHashToVotingPowerto determine themajorityParentHash.Since Go map iteration order is non-deterministic, if multiple parent hashes had
majorityVP, different nodes could pick differentmajorityParentHashvalues. -
Effect on consensus
-
Nodes that selected a valid majority parent hash would commit the milestone to state.
-
Nodes that selected the inflated parent hash would later fail a
PreBlockercheck and diverge.
As a result:
-
Some nodes would obtain a valid
pendingMilestone, -
Others would get
niland attempt to rotate the current span.
This disagreement on milestone propositions prevents validators from reaching consensus and can ultimately lead to a chain halt.
-
Issue 2 – Late malformed vote extensions causing halts
The second issue involved late-arriving, malformed vote extensions.
-
Interaction with
PrepareProposal-
The
PrepareProposalhandler callsValidateVoteExtensions. -
If vote extensions are invalid,
ValidateVoteExtensionsreturns an error andPrepareProposalfails. -
In our integration, this error propagates into CometBFT, leading to a
panicand halting the chain.
-
-
Mismatch with Cosmos/Comet semantics
In Cosmos/Comet:
-
Once the 2/3+ voting power threshold is reached, vote extensions are not revalidated at that stage.
-
They are directly added to the local commit.
Therefore, a faulty validator can:
-
Send a malformed vote extension late in the precommit phase of the previous block,
-
Have it included in the extended commit,
-
Cause the subsequent
PrepareProposalto fail whenValidateVoteExtensionsrejects the malformed data.
-
-
Concrete example
If a vote extension includes a side transaction response with an invalid transaction hash:
-
ValidateVoteExtensionswill fail, -
PrepareProposalwill return an error, -
The chain will halt even though 2/3+ voting power was already achieved.
-
Resolution and Recovery
A patch was released on Wednesday, November 12th, 2025 with Heimdall-v2 tag v0.4.4.
The main changes, implemented in PR #499, are:
-
Safer vote extension validation
-
ValidateVoteExtensionswas refactored and split so that it only returns an error (and thus triggers a Comet panic) when strictly necessary. -
Late malformed vote extensions no longer cause a chain halt once a block has already achieved the 2/3+ voting power threshold.
-
-
Deterministic milestone majority selection
-
Non-determinism in milestone majority selection was removed by:
-
Detecting and failing on duplicate block hashes during the milestone proposition phase, and
-
Ensuring deterministic handling of parent hashes and voting power.
-
-
-
Deployment
-
The patch was first tested on a dedicated devnet.
-
It was then deployed and verified on Amoy and Mainnet nodes.
-
A public release announcement was shared, instructing all validators to upgrade to
v0.4.4.
-