Audit report AR-29
Reported privately in an independent security review, 2026-09-03.
- Report date
- 2026-09-03
- Kind
- Bug
- Status on master
- Present
- Proposed issue state
- Open
Summary
The regtest-only -blockversion option is read as a 64-bit integer and then narrowed into the block header's 32-bit version, so an out-of-range value becomes a version that the node's own template check rejects, and template creation fails. The report is accurate. It needs an operator to set a debug option on a test chain, and it affects getblocktemplate and IPC templates alike; it is not an IPC bug. Small configuration fix, mergeable.
The report
On chains that mine blocks on demand (regtest), BlockAssembler::CreateNewBlock lets the operator override the block version with -blockversion=N. It reads the option with GetIntArg, which returns int64_t, and assigns the result to the header's int32_t nVersion. An out-of-range positive value such as 2147483648 wraps to a negative version, which the node then rejects when it validates its own template.
The report states that the operator must explicitly set the debug option on a mine-on-demand chain, that the effect is failed template creation while the node keeps running, resolved by restarting without the setting, and that there is no remote input, mainnet effect, crash, persistent corruption, funds loss or consensus effect.
The reproduction is a functional test case added to test/functional/mining_basic.py: it restarts the node with -blockversion=2147483648, calls getblocktemplate, and expects the version to be capped at 2**31 - 1. Before the fix the call fails with a template rejection.
Proposed change
Read the option through the typed int32_t accessor, whose parser handles the boundary, instead of narrowing later:
if (chainparams.MineBlocksOnDemand()) {
- pblock->nVersion = gArgs.GetIntArg("-blockversion", pblock->nVersion);
+ pblock->nVersion = gArgs.GetArg<int32_t>("-blockversion", pblock->nVersion);
}
Normal overrides and the default version are unchanged. The report notes that the change does not make every operator-chosen version consensus-valid, and does not change validation of received blocks.
Assessment
Present on Bitcoin Core master: pblock->nVersion = gArgs.GetIntArg("-blockversion", pblock->nVersion);. The fix is correct. It concerns block template creation in general, reached through getblocktemplate as well as the IPC mining interface, and only through an operator's regtest debug option. No stability effect; outside the survey's scope.
Status
Present on master. Next step: a one-line Bitcoin Core PR with the functional test. No public PR yet.
Reported privately in an independent security review on 2026-09-03.