89053 bc high wormhole miner volume fees are permanently unclaimable because the credit creates no zk tree leaf
Submitted on Aug 16th 2026 at 19:37:20 UTC by @tinnohofficial for Audit Comp | Quantus
Report ID: #89053
Report Type: Blockchain/DLT
Report severity: High
Target: https://github.com/immunefi-team/audit-comp-quantus-chain
Impacts:
Permanent freezing of unclaimed yield
Description
Brief/Intro
QPoW miners are paid to Poseidon-derived wormhole addresses. These addresses have no Dilithium signing key, so their funds can only be claimed through a ZK-tree leaf that commits the recipient and amount.
The wormhole pallet credits the miner's volume-fee share to the correct address, but does not create that leaf. The balance is visible in System::Account, yet the miner can neither sign from the address nor prove a wormhole exit for the fee. Every successfully credited miner volume fee is therefore permanently unclaimable without privileged recovery.
Vulnerability Details
Wormhole credits require a ZK-tree leaf
For a normal user exit, process_exit_bundle performs both required operations:
See pallets/wormhole/src/lib.rs:822-859.
record_transfer increments TransferCount and inserts a leaf containing the recipient, transfer count, asset ID, and exact amount:
See pallets/wormhole/src/lib.rs:1280-1310 and pallets/zk-tree/src/lib.rs:114-147.
Normal block rewards follow the same rule by calling record_transfer_proof immediately after minting: pallets/mining-rewards/src/lib.rs:230-237.
The miner-fee branch omits the leaf
The miner-fee branch only changes the balance and emits an event:
See pallets/wormhole/src/lib.rs:942-983. There is no record_transfer or record_transfer_proof call.
Nothing records the leaf indirectly:
increase_balanceis event-free, as documented atpallets/wormhole/src/lib.rs:822-827and tested byexit_credits_emit_no_scannable_transfer_events.MinerVolumeFeePaidis not one of the balance events scanned byWormholeProofRecorderExtension:runtime/src/transaction_extensions.rs:329-395.The settlement calls are bare unsigned extrinsics, so the extension's normal signed-transaction scan does not process them.
The credited address cannot spend normally
extract_author_from_digest derives the author with derive_wormhole_address(preimage): primitives/wormhole/src/lib.rs:122-150. MINING.md:41-48 confirms that mining rewards use this wormhole address.
The miner therefore has only two possible spend paths, and both are unavailable for this fee:
A normal balance transfer is impossible because no Dilithium signing key exists for the Poseidon-derived address.
A wormhole exit is impossible because no leaf commits the miner-fee amount.
A later block reward does not recover the fee. Its leaf commits only the later reward amount, not the account's full free balance.
Distinction from the public Eiger findings
This is not the previously reported author-derivation bug:
EQ-QNT-WORMHOLE-F-03reported that the pallet decoded the raw preimage as the author. That was fixed by deriving the correct wormhole address. The current code now credits the correct address, but still omits the leaf needed to claim the credit.EQ-QNT-WORMHOLE-F-05concerned missing signed transfer call variants in the proof recorder. This fee is an event-free internal balance credit inside a bare unsigned settlement call, so that fix does not cover it.
The current defect has a different root cause and requires a different fix: record a leaf for the correctly derived author.
Impact Details
The runtime assigns 50% of each computed wormhole volume fee to the block author: runtime/src/configs/mod.rs:728-738. Whenever that credit succeeds, the full miner share becomes permanently unclaimable.
The protocol emits MinerVolumeFeePaid and displays a real free balance, but the miner cannot spend or claim it. No later reward sweeps the missing amount. Recovery of already-stranded fees requires privileged governance or a storage migration.
This directly matches High - Permanent freezing of unclaimed yield: the frozen value is protocol-allocated miner-fee revenue, not user principal.
Recommended Fix
Record a transfer immediately after each successful miner-fee credit:
The settlement weight must also include this additional ZK-tree insertion. Previously stranded balances require a separate migration or privileged recovery.
References
pallets/wormhole/src/lib.rs:822-859- user exit credit followed byrecord_transfer.pallets/wormhole/src/lib.rs:942-983- miner-fee credit with no leaf.pallets/wormhole/src/lib.rs:1280-1330- leaf creation and transfer-count update.pallets/zk-tree/src/lib.rs:114-147- leaf fields, including the exact amount.pallets/mining-rewards/src/lib.rs:230-237- normal miner reward followed by proof recording.primitives/wormhole/src/lib.rs:97-150- wormhole author derivation.runtime/src/configs/mod.rs:728-738- volume-fee configuration.MINING.md:41-48- miner rewards use derived wormhole addresses.
Proof of Concept
The PoC submits the pallet's production private-batch fixture through the real verify_private_batch call. In the same settlement:
The user exit receives a balance and
TransferCount = 1, proving its leaf was inserted.The block author receives the miner fee but remains at
TransferCount = 0, proving no leaf was inserted.A second test shows that a later block-reward leaf commits only the reward and does not cover the stranded fee.
Run
From audit-comp-quantus-chain:
Observed Output
Tested against frozen chain commit 3b243b8:
PoC Code
Was this helpful?