← Back to list
● Based on the 2026-09-24 Bitget hack ($387.5M)

I reproduced the Bitget hack exactly,
and I'm publishing the code that stops it

I built a price-time priority matching engine from scratch, plus the defense logic that stops the exact attack pattern used in the Bitget hack: a small test withdrawal, then compromised admin-backend credentials, then forged mass withdrawals. Both are free right now.

See live demo → Jump to code

Who this is for

Not for real exchange operators — this is a learning resource for backend developers prepping for systems-design interviews or who want a meaty portfolio project. Matching-engine design is a recurring interview topic at companies like Coinbase and Robinhood.

2,226★
GitHub stars on the open-source matching engine exchange-core
387.5M$
Real damage from the Bitget hack this code reproduces
$0
What this code costs right now — free

Code — matching-engine.js

A minimal matching engine that fills buy/sell orders by price-time priority.

matching-engine.js
// Minimal price-time priority matching engine
class MatchingEngine {
  constructor() {
    this.buyBook = []; // bids: price desc, then time asc
    this.sellBook = []; // asks: price asc, then time asc
    this.fills = [];
  }

  addOrder(side, price, qty) {
    const order = { id: crypto.randomUUID(), side, price, qty, time: Date.now() };
    if (side === 'buy') {
      this.buyBook.push(order);
      this.buyBook.sort((a, b) => b.price - a.price || a.time - b.time);
    } else {
      this.sellBook.push(order);
      this.sellBook.sort((a, b) => a.price - b.price || a.time - b.time);
    }
    this.match();
    return order;
  }

  match() {
    while (this.buyBook.length && this.sellBook.length && this.buyBook[0].price >= this.sellBook[0].price) {
      const buy = this.buyBook[0], sell = this.sellBook[0];
      const qty = Math.min(buy.qty, sell.qty);
      buy.qty -= qty; sell.qty -= qty;
      this.fills.push({ price: sell.price, qty, buyId: buy.id, sellId: sell.id, time: Date.now() });
      if (buy.qty <= 0) this.buyBook.shift();
      if (sell.qty <= 0) this.sellBook.shift();
    }
  }
}

Code — withdrawal-defense.js

Defends the Bitget (2026-09) pattern: velocity check + multi-approval + timelock.

withdrawal-defense.js
// Forged-withdrawal defense — modeled on the Bitget (2026-09) incident
class WithdrawalGuard {
  constructor({ velocityWindowMs = 10000, velocityThreshold = 3, timelockMs = 10000 } = {}) {
    this.recent = [];
    this.velocityWindowMs = velocityWindowMs;
    this.velocityThreshold = velocityThreshold;
    this.timelockMs = timelockMs;
  }

  request(amount, approvals = 1) {
    const now = Date.now();
    this.recent = this.recent.filter(r => now - r.time < this.velocityWindowMs);
    this.recent.push({ amount, time: now });

    // 1) Velocity check: too many requests in a short window
    if (this.recent.length > this.velocityThreshold) {
      return { status: 'blocked', reason: 'velocity_check' };
    }

    // 2) Multi-approval: large amounts can't clear on one admin's authority
    const requiredApprovals = amount > 1000 ? 2 : 1;
    if (approvals < requiredApprovals) {
      return { status: 'pending', reason: 'multi_approval_required' };
    }

    // 3) Timelock: large withdrawals are delayed, not instant
    if (amount > 1000) {
      return { status: 'timelocked', releaseAt: now + this.timelockMs };
    }

    return { status: 'approved' };
  }
}

Price

Free (for now)
A deeper version (multi-symbol, production deployment guide, tests) ships later — pay-what-you-want, starting at $0.
goalsgo7574@gmail.com
This isn’t a purchase — just email me "notify me about the paid version" and I’ll reach out when it ships.
Note: This is a scaled-down learning implementation. No concurrency handling, no persistence, no real traffic handling — don't drop this into a real exchange or wallet system.

Leave feedback

Questions or feedback about this product? Leave your email if you'd like a reply (optional).