The Wallet Library That Killed Itself — JavaScript Bug Hunt

Modelled on the Parity multisig wallet freeze (November 2017): the shared library contract's initialiser was never claimed, so an anonymous account called…

  • Language: JavaScript
  • Layer: Backend
  • Difficulty: Hard
  • Concepts: Access Control, Initialization
  • Modelled on: Parity multisig · 2017
  • Visible tests: the first initialisation succeeds; re-initialisation is refused; only the owner may destroy
  • Reward: 50 XP for a complete fix

Briefing

Modelled on the Parity multisig wallet freeze (November 2017): the shared library contract's initialiser was never claimed, so an anonymous account called it, became the owner, and then invoked kill. Every wallet that delegated to that library was bricked, freezing roughly 513,000 ETH permanently.

wallet.js exposes an initialiser that anyone can call at any time.

Fix the library so ownership can only be set once, and only destructive operations the owner performs are allowed.

Bug report

BUG-PARITY · Priority: Critical (funds frozen) · Reported by: security

The library must behave like this:

  • initialize(lib, owner) sets the owner only if there is not one already; it returns true on success and false if the library is already initialised
  • destroy(lib, caller) sets lib.dead = true only when caller is the owner and returns true; otherwise it changes nothing and returns false

Observed: initialize can be called repeatedly by anyone, so an attacker simply re-initialises to themselves and calls destroy.

Logs

[wallet] initialize called by 0xdevops237 on an already-initialised library
[wallet] destroy succeeded; 587 dependent wallets now unusable

The code as shipped

src/wallet/wallet.js (editable)

// Shared multisig library.
exports.initialize = function (lib, owner) {
  lib.owner = owner;
  return true;
};

exports.destroy = function (lib, caller) {
  lib.dead = true;
  return true;
};

Read-only context: src/wallet/THREAT.js.

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