DEV Community

Cover image for Your Swap Service Is on the Laundering Path: Engineering Notes From the Bitget and NEAR Intents Incidents
Nefi Swap
Nefi Swap

Posted on

Your Swap Service Is on the Laundering Path: Engineering Notes From the Bitget and NEAR Intents Incidents

Within one week, NEAR Intents, a cross-chain swap protocol that had processed more than $30 billion across 35 chains, was on both sides of a security incident.

After Bitget's September 24 breach, about $50 million of stolen funds tried to route through the protocol and was stopped. On October 1, NEAR Intents was exploited itself for about $3.8 million, through a bug in how its Omni deposit and withdrawal infrastructure interacted with the Intents smart contract. Investigators traced the exploit to irregular outflows from a BNB Chain hot wallet, and the team froze deposits and withdrawals on 11 networks while it patched.

If you build or operate any swap or bridge service, both halves of that week are design inputs. Here's what they suggest.

1. Screen before execution, not after

Stolen funds arrive looking like any other deposit. The only point where you can stop them cheaply is before you execute the swap and send the output on-chain. After that, you're chasing.

Model screening as an explicit state in your order lifecycle:

awaiting_deposit → deposit_detected → screening → (cleared | held) → executing → sent
Enter fullscreen mode Exit fullscreen mode

The important part is held. It needs a defined exit path (refund, manual review, or release) and a user-visible status. An order that silently stalls looks identical to a scam from the user's side.

2. Pause per network, not globally

NEAR Intents froze deposits and withdrawals on 11 specific networks rather than shutting everything down. Their co-founder said the exploit was isolated to USDT on BSC. Network-level granularity let unaffected routes keep running.

If your only kill switch is "stop the service," every incident becomes a full outage.

3. Limit hot-wallet outflow velocity

The NEAR Intents exploit started with irregular outflows from a hot wallet. An outflow guard that tracks volume per network in a rolling window, and trips a pause automatically, bounds how much an exploit can drain before a human looks at it:

export class OutflowGuard {
  constructor({ windowMs, limits }) {
    this.windowMs = windowMs;   // e.g. 10 * 60 * 1000
    this.limits = limits;       // { "BSC": 250000, "TRON": 400000 } in USD
    this.events = new Map();    // network -> [{ ts, usd }]
    this.paused = new Set();
  }

  allow(network, usd, now = Date.now()) {
    if (this.paused.has(network)) return false;

    const limit = this.limits[network];
    if (limit === undefined) return false; // unknown network: fail closed

    const recent = (this.events.get(network) ?? [])
      .filter((e) => now - e.ts < this.windowMs);

    const total = recent.reduce((sum, e) => sum + e.usd, 0);
    if (total + usd > limit) {
      this.paused.add(network);
      return false;
    }

    recent.push({ ts: now, usd });
    this.events.set(network, recent);
    return true;
  }

  resume(network) {
    this.paused.delete(network);
  }
}
Enter fullscreen mode Exit fullscreen mode

Notes for production:

  • This is in-memory; put state somewhere shared if you run multiple signers
  • Fail closed on unknown networks, as above
  • Tripping the guard should page a human and flip the network's public status, not just block quietly
  • Set limits from historical peak volume per network, not round numbers

4. Separate the deposit path from the contract logic

The NEAR Intents bug sat in the interaction between deposit infrastructure and contract logic, not in either one alone. Integration boundaries deserve their own tests: replayed deposits, duplicated callbacks, amounts that don't match the order, and deposits arriving on a network the order didn't expect.

5. Publish status like an API

During incidents, users need one machine-readable source of truth: which networks accept deposits right now. A simple /status endpoint with per-network flags, consumed by your own UI and bots, prevents users from sending funds into a paused route and gives partners something to integrate against.

6. Plan for the "refund scam" phase

Every public incident is followed by fake compensation messages. Decide in advance where compensation will be announced, state that you will never contact users first about it, and put that statement on the status page before you need it.


Disclosure: written by the NefiSwap team. NefiSwap runs no-account crypto-to-crypto swaps where no-KYC doesn't mean no-AML: transactions can be screened and flagged funds held for review. nefiswap.com

Top comments (0)