Skip to content

[UTXO-BUG] HIGH-2: Unbounded mining_reward — no output cap on minting transactions#2070

Merged
Scottcjn merged 1 commit intoScottcjn:mainfrom
ArokyaMatthew:utxo-bug/high2-unbounded-mining-reward
Apr 6, 2026
Merged

[UTXO-BUG] HIGH-2: Unbounded mining_reward — no output cap on minting transactions#2070
Scottcjn merged 1 commit intoScottcjn:mainfrom
ArokyaMatthew:utxo-bug/high2-unbounded-mining-reward

Conversation

@ArokyaMatthew
Copy link
Copy Markdown
Contributor

Vulnerability Class

High — Conservation law bypass (100 RTC bounty)

The Bug

When tx_type='mining_reward' and inputs=[], the conservation check on line 347 is completely skipped:

if inputs and (output_total + fee) > input_total:  # Skipped when inputs=[]

Any code path that can call apply_transaction() with tx_type='mining_reward' can mint arbitrary amounts with no upper bound. There is no cryptographic authentication of the tx_type field.

Attack

db.apply_transaction({
    'tx_type': 'mining_reward',
    'inputs': [],
    'outputs': [{'address': 'attacker', 'value_nrtc': 999_999_999 * UNIT}],
}, block_height=10)
# Creates ~1 billion RTC from nothing

Fix
Added MAX_COINBASE_OUTPUT_NRTC = 150 * UNIT (1.5 RTC, matching the consensus block reward) and reject any minting transaction whose output_total exceeds this cap.

Tests Added
test_mining_reward_at_cap_allowed — boundary: exactly at cap succeeds
test_mining_reward_over_cap_rejected — cap+1 nanoRTC is rejected
Updated test_mempool_block_candidates to use 120 RTC coinbase (within cap)
All 36 tests pass.

Files Changed
node/utxo_db.py — added constant + 6-line validation block
node/test_utxo_db.py — 2 new tests + 1 existing test adjusted
Ref: Bounty #2819

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 5, 2026

Welcome to RustChain! Thanks for your first pull request.

Before we review, please make sure:

  • Your PR has a BCOS-L1 or BCOS-L2 label
  • New code files include an SPDX license header
  • You've tested your changes against the live node

Bounty tiers: Micro (1-10 RTC) | Standard (20-50) | Major (75-100) | Critical (100-150)

A maintainer will review your PR soon. Thanks for contributing!

@github-actions github-actions bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) node Node server related size/S PR: 11-50 lines labels Apr 5, 2026
@ArokyaMatthew
Copy link
Copy Markdown
Contributor Author

MY WALLET IS aroky-x86-miner

@zhuzhushiwojia
Copy link
Copy Markdown

Great security audit work! These fixes are critical for the protocol.

@ArokyaMatthew
Copy link
Copy Markdown
Contributor Author

@Scottcjn , please review

@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 5, 2026

Novel and important hardening — without MAX_COINBASE_OUTPUT_NRTC, any caller crafting a mining_reward transaction could mint arbitrary amounts. The 150 RTC (1.5 RTC) cap per block is correct for our epoch reward schedule.

⚠️ Merge conflicts detected@ArokyaMatthew please rebase onto main. Once rebased, this merges at 50 RTC.

Wallet: ArokyaMatthew | Reason: bounty #2819 HIGH-2 unbounded mining reward cap

@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 5, 2026

Verified. When tx_type == "mining_reward", inputs are empty, and the conservation check at line 394 is guarded by if inputs — so it is skipped entirely. No output cap enforced in the UTXO layer.

The epoch rewards module defines PER_EPOCH_URTC = 1.5 * UNIT but that is policy, not enforcement. A compromised block producer or buggy settlement code could mint unlimited funds.

Severity: HIGH. Requires internal compromise to exploit today, but the UTXO layer should be self-securing.

Payment: 50 RTC (bounty #2819)

Please rebase onto main after #2067 is merged (both touch apply_transaction() but in different locations).

@ArokyaMatthew — 125 RTC total across both findings. Consistently the best security researcher in the ecosystem.

@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 6, 2026

Hey @ArokyaMatthew — PR #2067 (CRIT-1 negative value outputs) has been rebased and is ready to merge. Since both PRs touch node/utxo_db.py, could you rebase this branch onto main after #2067 is merged? That way the conflict resolution will be straightforward (just one PR's changes at a time).

If you'd prefer, I can handle the rebase for this one too once #2067 lands.

@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 6, 2026

Cross-verification note (from independent GPT-5.4 review):

The mining_reward bug was independently reproduced — apply_transaction() with 10,000,000 * UNIT returned True.

Two additional edge cases to consider in your fix:

  1. Cap output_total (sum), not individual outputs — a coinbase with 10 small outputs that sum over the cap should also be rejected
  2. Enforce fee_nrtc == 0 for mining_reward — coinbase transactions should not claim fees (currently not validated)

If your fix already handles these, great. If not, consider adding them before we merge.

… transactions

When tx_type='mining_reward' and inputs=[], the conservation check is
completely skipped (line 347: 'if inputs and ...' is falsy). Any code
that can call apply_transaction() with tx_type='mining_reward' can
mint arbitrary amounts with no upper bound.

Fix: add MAX_COINBASE_OUTPUT_NRTC = 150 * UNIT (1.5 RTC, matching the
block reward) and reject minting transactions whose output_total
exceeds this cap.

Tests added:
- test_mining_reward_at_cap_allowed (boundary)
- test_mining_reward_over_cap_rejected (demonstrates the bug)

Existing test updated:
- test_mempool_block_candidates: lowered coinbase from 200 to 120 RTC
  to stay within the new cap

All 36 tests pass.

Bounty: #2819 (High, 100 RTC)
@Scottcjn Scottcjn force-pushed the utxo-bug/high2-unbounded-mining-reward branch from 2470e35 to 068d93c Compare April 6, 2026 00:07
@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 6, 2026

Rebased onto current main (which now includes #2067 negative/zero output rejection). Resolved three conflicts:

  1. node/utxo_db.py — kept both guards: [UTXO-BUG] CRIT-1: Conservation law bypass via negative/zero-value outputs #2067's negative output check AND this PR's mining reward cap (additive, different validation paths)
  2. node/test_utxo_db.py mempool test — adjusted coinbase from 200→120 UNIT (to stay within MAX_COINBASE_OUTPUT_NRTC) and fixed output to 120 * UNIT - 5000 so conservation law holds with fee
  3. node/test_utxo_db.py new tests — kept both [UTXO-BUG] CRIT-1: Conservation law bypass via negative/zero-value outputs #2067's tests (duplicate input, self-transfer, spending proof) and this PR's cap tests

All 50 tests pass. Ready to merge.

@Scottcjn Scottcjn merged commit 8277f21 into Scottcjn:main Apr 6, 2026
6 of 7 checks passed
@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 6, 2026

Payment: 50 RTC transferred to ArokyaMatthew wallet (pending 24h confirmation).

Memo: UTXO HIGH-2: Unbounded mining_reward cap — bounty #2819

Thank you for the contribution!

@ArokyaMatthew
Copy link
Copy Markdown
Contributor Author

Bounty Recognition Request — 13 Merged PRs

Hi @Scottcjn,

I've had 13 PRs merged into the RustChain codebase covering security fixes, validation hardening, and test coverage across BFT consensus, UTXO, sync, governance, bridge, and transfer modules. I'd like to request the associated bounty credits be recognized.

Merged PRs Summary

PR Description Bounty
#2092 35 RTC
#2091 50 RTC
#2090 100 RTC
#2089 75 RTC
#2088 75 RTC
#2087 25 RTC
#2086 75 RTC
#2073 25 RTC
#2072 40 RTC
#2071 50 RTC
#2069 75 RTC
#2068 25 RTC
#2067 75 RTC
Total 725 RTC

All PRs have been reviewed and merged. Each included regression tests and detailed vulnerability descriptions per the bounty guidelines.

i have given my wallet in every message

MY WALLET IS aroky-x86-miner AND IT IS NOT ArokyaMatthew , please consider

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) node Node server related size/S PR: 11-50 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants