57055 bc medium dos via p2p during block header validation using bad proof
Submitted on Oct 23rd 2025 at 04:37:38 UTC by @emarai for Attackathon | VeChain Hayabusa Upgrade
Report ID: #57055
Report Type: Blockchain/DLT
Report severity: Medium
Target: https://github.com/vechain/thor/compare/v2.3.2...release/hayabusa
Impacts:
Network not being able to confirm new transactions (total network shutdown)
Description
Brief/Intro
Malicious node is able to crash their peers using bad signature proof, causing network shutdown.
Vulnerability Details
During block validation the receiving node will check if the header proof is correct. The validation code will call Beta() which will call vrf.Verify. The Verify() function will cause the node crash if provided a bad proof. What is a bad proof here? The bad proof is a proof with a valid gamma, but with invalid c and s (all-zero c and s). For more details, see the PoC section.
Relevant code snippets:
func (c *Consensus) validateBlockHeader(header *block.Header, parent *block.Header, nowTimestamp uint64) error {
...
if _, err := header.Beta(); err != nil {
return consensusError(fmt.Sprintf("block VRF signature invalid: %v", err))
}Impact Details
An attacker can deliberately send a block with a bad proof (all zero c and s) and crash the receiving target node. Anyone can send any block, and the receiving end will validate it, making this a practical denial-of-service vector.
References
https://github.com/vechain/thor/blob/9467aff0f1eb5aedb2c113f096e2cc2531fa3e82/consensus/validator.go#L140
https://github.com/vechain/thor/blob/9467aff0f1eb5aedb2c113f096e2cc2531fa3e82/block/header.go#L254
Proof of Concept
Honest network
Let's use the networkhub for the honest network.
Copy this file into cmd/main.go
Run the honest network using this, keep it in the background:
Attacker node
Clone the current thor node, current commit is fd2b8d4b338c3d2b9bd947f5e1802f5e9383fed5
Also the PoC patches modify packer loop and propagation to make the attacker more likely to propose and broadcast blocks. Example diffs (applied in PoC):
cmd/thor/node/packer_loop.go— force pack condition to truecomm/communicator.go— propagate to all peers instead of subsetpoa/sched_v2.go— bypass proposer checks
(Full patch snippets are included in the original PoC description and reproduced below.)
Patch excerpts applied in PoC (selected hunks):
Genesis file for the local attacker network
Save this as genesis_local.json:
Build and run the attacker node:
Notes / Observations
The crash occurs inside the VRF verify routine when provided a malformed proof: gamma present, but c and s zeroed. The code path leads to a nil pointer dereference in math/big operations inside go-ecvrf.
Because block headers are validated upon receipt and any peer can send blocks via P2P, this allows an attacker to crash peers by sending such crafted blocks.
Was this helpful?