Back to the blog
SecurityBunCrypto

The $5.6B Binance hack: a security lesson for Bun

October 30, 2026·6 min read·Diego Horvatti

A wallet showed up on Arkham labeled "Binance-hacker-1029" with a scary number next to it: $5.6 billion attributed to a Binance hack. I opened the entity page on Arkham Explorer and stared at that number for a while. This post won't pretend to be a blockchain forensics expert. I want to talk about what this kind of case teaches people who write backend code. In my case, that means Bun.

What we know about the Binance hack so far

I'll be honest with you. The only concrete thing is a public label on an on-chain explorer. Arkham groups addresses into "entities" and gives them names. In this case, the name says it's a hacker and that the money came from Binance.

I haven't seen a confirmed technical report explaining how it happened. I also don't know if the $5.6 billion is the value at the time of the theft or the current value of the assets. In crypto, that gap is often huge. So treat the number as approximate until an official post-mortem comes out.

Even so, there's a lesson here. Most big exchange thefts fall into a few categories:

  • a hot wallet private key that leaked or was poorly stored;
  • a compromised employee machine;
  • a malicious dependency in the build chain;
  • no alert for abnormal outflows of funds.

None of them needs a brilliant zero-day. Most of the time the attacker just walks through a door someone left open.

Why a Bun dev should care

Maybe you're thinking: "I don't run an exchange, I build a scheduling API". Fair. But the attack pattern is the same. Only the size of the loss changes.

Your project has a Stripe key. It has a database access token. It has an AWS or Vercel service account. If someone grabs those, the damage happens in minutes, just the same.

And JavaScript has a long-standing problem here. Any npm package can run code on your machine during install. In recent years, popular packages were hijacked to steal exactly that: environment variables and wallet keys.

Attackers don't break into the vault. They look for the key someone forgot in the door.

What Bun already does for you at install time

This is where Bun has a real advantage. I use it as an argument when people ask why I switched.

bun install does not run lifecycle scripts (postinstall and friends) from dependencies by default. It only runs them for packages you explicitly allow in trustedDependencies in package.json:

{
  "trustedDependencies": ["esbuild", "sharp"]
}

This closes the most common door for supply chain attacks in the JS ecosystem. A compromised package deep in your tree can't run anything just because it was installed.

Two things worth adding to your CI today:

bun install --frozen-lockfile
bun audit

--frozen-lockfile makes the build fail if the lockfile doesn't match package.json. Nobody swaps a dependency version behind your back. bun audit checks your packages against the database of known vulnerabilities.

It's not a silver bullet. A malicious package can still attack when it's imported at runtime. But you take out the most common and cheapest case for the attacker.

How to keep secrets out of .env

This is what bothers me most in other people's projects. The .env turns into a chest with everything inside. It sits on disk in plain text, and one day someone commits it by accident.

For local development, Bun 1.3 introduced Bun.secrets, which uses the operating system's vault (Keychain on macOS, libsecret on Linux, Credential Manager on Windows):

import { secrets } from "bun";

await secrets.set({
  service: "my-app",
  name: "stripe-key",
  value: "sk_test_...",
});

const stripeKey = await secrets.get({
  service: "my-app",
  name: "stripe-key",
});

In practice, the key leaves the file that any script can read with cat. For production, keep using your platform's manager (Vercel environment variables, AWS Secrets Manager, Vault). The rule is simple: real secrets don't live in the repo and don't live in loose files.

Three more habits that cost very little:

  • one key per environment and per service, never the same key for everything;
  • least privilege: the email worker's token doesn't need write access to the database;
  • rotation with a date on the calendar, not "whenever".

Monitoring what goes out matters as much as protecting what comes in

Notice one thing. On the blockchain, everyone saw the money leaving. That's how Arkham was able to label the wallet. The problem is that seeing it later gives nothing back.

The same logic applies to your system. You need an alarm that fires when something goes off the rails: too many refunds, too many data exports, a user downloading the whole database at three in the morning.

A simple alert in Bun covers the basics. Something like this, running as a cron job:

const LIMIT_PER_HOUR = 50_000; // in cents, adjust to your business

const res = await fetch(`${Bun.env.INTERNAL_API}/withdrawals?last_hour=1`, {
  headers: { Authorization: `Bearer ${Bun.env.READ_TOKEN}` },
});
const withdrawals: { amount: number }[] = await res.json();

const total = withdrawals.reduce((sum, w) => sum + w.amount, 0);

if (total > LIMIT_PER_HOUR) {
  await fetch(Bun.env.SLACK_WEBHOOK!, {
    method: "POST",
    body: JSON.stringify({ text: `Abnormal outflow: ${total / 100} in the last hour` }),
  });
}

Important detail: this script's token is read-only. If the monitor gets compromised, the attacker can see the numbers and nothing else. And an alert that warns you in 10 minutes is worth more than a beautiful dashboard nobody opens.

If your system handles money, you can go further and add a hard limit. Above a certain amount, the operation stays pending until a human approves it. Annoying? A bit. But approving a withdrawal is much cheaper than explaining to a customer why their money vanished.

What I'd change in your project today

If you have 30 free minutes today, I'd go in this order:

  1. Run bun audit and actually read the output.
  2. Check trustedDependencies and remove anything that doesn't need to be there.
  3. Add --frozen-lockfile to the pipeline.
  4. Look for leaked secrets in your git history (git log -p | grep -i "sk_live" already scares a lot of people).
  5. Create one alert, just one, for the most sensitive operation in your system.

None of these steps depends on you working with crypto. All of them reduce the damage if someone ever gets in.

My take on the case

We still need the official report to know what happened. It could be a leaked key. It could be social engineering. It could be something new. My guess is it'll be something boring, because it almost always is.

What annoys me about this kind of news is the usual reaction. Everyone talks about how big the number is and almost nobody reviews their own project. Whether the key guards $5.6 billion or 5,000 reais, the mistake is usually the same. The difference is that yours won't make headlines. It'll just cost you a weekend.

Bun helps with safer defaults at install time and with Bun.secrets. But no tool fixes a key pasted into a forgotten file. Your discipline does. If you want to see how I apply this in production, take a look at the projects I maintain.

LinkedIn summary

$5.6 billion left a giant exchange, and I bet the mistake was something really boring.

There's no official report on the Binance hack yet. But almost every big theft starts with a leaked key, a malicious dependency or a missing alert.

Your project may not hold billions. But it has a Stripe key, a database token and AWS access. The attack is the same. Only the size of the damage changes.

In Bun I start with the basics: a lean trustedDependencies, --frozen-lockfile in CI, bun audit and Bun.secrets to get the key out of .env.

And one alert, just one, on the most sensitive operation. Watching the money leave after the fact won't bring any of it back.

I wrote the full step by step on the blog. If you have 30 minutes today, it's worth reviewing your project.

#Bun #InfoSec #JavaScript #Backend #DevSecOps