Skip to content

[UTXO-BUG] CRITICAL: Empty outputs allow fund destruction (200 RTC)#2120

Merged
Scottcjn merged 3 commits intoScottcjn:mainfrom
yuzengbaao:fix/utxo-empty-outputs-fund-destruction
Apr 6, 2026
Merged

[UTXO-BUG] CRITICAL: Empty outputs allow fund destruction (200 RTC)#2120
Scottcjn merged 3 commits intoScottcjn:mainfrom
yuzengbaao:fix/utxo-empty-outputs-fund-destruction

Conversation

@yuzengbaao
Copy link
Copy Markdown
Contributor

@yuzengbaao yuzengbaao commented Apr 6, 2026

No description provided.

CRITICAL vulnerability fix for Issue #2819

### Vulnerability
Empty outputs bypass conservation check:
- outputs=[] + fee=0 → output_total=0
- Check: (0 + 0) > input_total → False (bypassed)
- Result: Inputs spent, no outputs created → funds destroyed

### Impact
- Severity: CRITICAL (200 RTC)
- 100% fund destruction possible
- Violates conservation law

### Fix
Add empty outputs check before conservation validation

### Testing
- ✅ Added test case: test_utxo_empty_outputs_bug.py
- ✅ All 50 existing tests still pass
- ✅ PoC test confirms vulnerability is fixed

**Bounty**: #2819 - Red Team UTXO Implementation
**Reporter**: XiaZong (RTC0816b68b604630945c94cde35da4641a926aa4fd)
**Tier**: BCOS-L2
Copilot AI review requested due to automatic review settings April 6, 2026 05:33
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 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/M PR: 51-200 lines labels Apr 6, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a critical UTXO validation flaw where transfer transactions with outputs=[] could spend inputs without creating any outputs, effectively destroying funds and violating conservation-of-value.

Changes:

  • Reject transactions with empty outputs in UtxoDB.apply_transaction() to prevent fund destruction.
  • Add a regression test that reproduces the empty-outputs exploit and asserts it is rejected.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
node/utxo_db.py Adds an explicit outputs non-empty validation during transaction application.
node/test_utxo_empty_outputs_bug.py Adds a standalone regression test covering the empty-outputs vulnerability.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +391 to +396
# CRITICAL FIX: Reject empty outputs to prevent fund destruction
# Without this check, outputs=[] bypasses conservation law
# and results in complete fund destruction
if not outputs:
conn.execute("ROLLBACK")
return False
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply_transaction() now rejects transactions with outputs=[], but mempool_add() still admits them (it allows outputs=[] because output_total becomes 0). This reintroduces the exact mempool DoS the mempool conservation checks are trying to prevent: an attacker can submit an outputs=[] tx that will later fail apply_transaction(), but still locks the input UTXOs in utxo_mempool_inputs until expiry. Mirror this empty-outputs rejection (and ideally the same per-output value validation) in mempool_add() to keep admission criteria aligned with apply_transaction().

Copilot uses AI. Check for mistakes.
import sys
import time

# Add parent directory to path for imports
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says this adds the parent directory to sys.path, but os.path.dirname(os.path.abspath(file)) is the current file’s directory (the node/ folder). Either update the comment to reflect what’s being added, or change the path insertion to actually add the parent directory if that’s what’s intended.

Suggested change
# Add parent directory to path for imports
# Add this file's directory to path for imports

Copilot uses AI. Check for mistakes.
CRITICAL + MEDIUM vulnerability fixes for Issue #2819

**apply_transaction()**: Reject empty outputs (CRITICAL)
**mempool_add()**: Reject empty outputs (MEDIUM - defense in depth)

Testing: 50/50 existing tests + 2 new PoC tests pass
@github-actions github-actions bot added the size/L PR: 201-500 lines label Apr 6, 2026
@yuzengbaao
Copy link
Copy Markdown
Contributor Author

📝 Bounty Reference Clarification

Correct Bounty Issue: Scottcjn/rustchain-bounties#2819

The bounty issue referenced in this PR is located in the rustchain-bounties repository (specs-only repo), not in the Rustchain repository (code repo).

Bounty Details:

Why the reference appears broken:

Reporter: XiaZong (RTC0816b68b604630945c94cde35da4641a926aa4fd)

@Scottcjn Scottcjn merged commit 042daec into Scottcjn:main Apr 6, 2026
7 of 8 checks passed
@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 6, 2026

Merged. Payment: 50 RTC

Good UTXO red team finding. The empty outputs bypass of the conservation law check is a real vulnerability. Fix is clean and well-tested.

Payment: 50 RTC to wallet RTC0816b68b604630945c94cde35da4641a926aa4fd

Note: Reduced from 200 RTC bounty claim to 50 RTC because:

  • The fix itself is 14 lines (simple guard clause)
  • The vulnerability was already partially documented in existing red team bounties
  • Tests are good but the core finding is a single missing validation

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/L PR: 201-500 lines size/M PR: 51-200 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants