184 Billion Coins From Nowhere — JavaScript Bug Hunt

Modelled on the Bitcoin value overflow incident (CVE-2010-5139, 15 August 2010): a transaction with two enormous outputs made their sum overflow a signed…

  • Language: JavaScript
  • Layer: Backend
  • Difficulty: Medium
  • Concepts: Overflow, Validation
  • Modelled on: Bitcoin · CVE-2010-5139
  • Visible tests: an ordinary spend is accepted; an overflowing pair of outputs is rejected
  • Reward: 50 XP for a complete fix

Briefing

Modelled on the Bitcoin value overflow incident (CVE-2010-5139, 15 August 2010): a transaction with two enormous outputs made their sum overflow a signed 64-bit integer and wrap to a small number, so the "outputs must not exceed inputs" check passed. Block 74638 created 184.467 billion BTC out of nothing, and the chain had to be forked.

ledger.js validates a transaction the same way — by summing outputs and comparing.

Fix validate so a wrapped or absurd total cannot pass.

Bug report

BUG-VALUEOVERFLOW · Priority: Critical · Reported by: consensus

validate(inputTotal, outputs) returns true only if the outputs are a legitimate spend:

  • every output must be strictly positive and at most MAX_MONEY
  • the sum of the outputs must be at most inputTotal

Observed: two outputs just under the wrap point sum to a small positive number and the transaction is accepted, minting money from nothing.

Logs

[consensus] accepted tx outputs=[9223372036854775806, 9223372036854775806] inputTotal=50
[consensus] supply increased by 1.844e+11

The code as shipped

src/chain/ledger.js (editable)

var MAX_MONEY = 2100000000000000;
exports.MAX_MONEY = MAX_MONEY;

// Wraps like a fixed-width signed integer would.
function addWrapping(a, b) {
  var sum = a + b;
  if (sum > MAX_MONEY * 4) sum = sum - MAX_MONEY * 8;
  return sum;
}

exports.validate = function (inputTotal, outputs) {
  var total = 0;
  for (var i = 0; i < outputs.length; i++) {
    total = addWrapping(total, outputs[i]);
  }
  return total <= inputTotal;
};

Read-only context: src/chain/CONSENSUS.js.

Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.