HOT Bridge / NEAR Intents

Research Incident Analysis
HOT Bridge / NEAR Intents

Incident Summary

On 30 September 2026, HOT Omni Bridge on NEAR was exploited, resulting in five observed BSC treasury payouts totaling $3.86M USD.

The attacker used a large pre-existing balance of a custom auxiliary token to request refunds far greater than the amounts in a new deposit. Recording the resulting large decimal amounts expanded the refund event beyond NEAR's 16384 bytes log limit and failed the Intents deposit resolver. HOT subsequently returned the original deposited backing, including USDT, while the Intents credit created by an earlier successful receipt survived.

Addresses and roles

Chain Address or account Established role
BSC 0x09fd1f5d9f185067a92493e43aa259ea4ab3ad37 Exploiter, receiving $3.865M
BSC 0x233c5370CCfb3cD7409d9A3fb98ab94dE94Cb4Cd HOT Bridge treasury
NEAR 20e6bfe4685d99004fc2095d3a0fc6158cd810ce8f801196141e183ed6e19d65 Exploiter, initiating the batch deposits and cash-out requests; recipient of returned backing.
NEAR dd1fe58ec316ada5b673b88c14fe2fa2b7ede82080440901dfbd64b994241757 Exploiter contract, internal credit recipient and notification callback contract.
NEAR 873518f0f5cf120d7a8e2a416337bba16d7ae622e91f7da3862f07e89dc2ba9e Exploiter contract Later internal credit recipient in the verified October 1 sequences. Abbreviated 8735….
NEAR v2_1.omni.hot.tg HOT's bridge contract and NEP-245 multi-token representation ledger.
NEAR intents.near Intents Verifier contract and internal user-balance ledger.

Background

HOT Bridge, also called HOT Omni Bridge, connects external-chain assets to NEAR and integrates with NEAR Intents for exchanges. Its public SDK is @hot-labs/omni-sdk. Three accounting layers are relevant: Actual external-chain asset in HOT treasury → HOT-issued token representation on NEAR → User's internal balance in intents.near

A normal inbound deposit works as follows:

  1. The user deposits the actual asset on its source chain
  2. HOT validates the deposit and authorizes its NEAR claim.
  3. HOT creates the corresponding representation on NEAR.
  4. Those tokens are deposited into Intents, which credits the user’s internal balance.

The Intents deposit code also supports an optional receiver notification. It credits the account first, then calls the receiving application, which may request that some deposited amounts be refunded. For a normal refund, Intents must remove the corresponding internal credit before returning its backing. Its resolver burns the unused credit and reports the unused amounts to HOT; HOT then returns those representations to the original sender. Accepting a 10-USDT deposit should leave both 10 USDT of backing and 10 USDT of internal credit. Refunding it fully should leave neither additional backing nor additional credit.

The incident broke the connection between the second and third layers: HOT returned the NEAR representation backing a deposit while Intents retained the user’s credit. Subsequent bridge withdrawals could then draw on treasury assets through ordinary withdrawal machinery.

Attack Flow

1. Preparation

On 29 September, the attacker claimed 10 BSC USDT on NEAR through 9SiSBv…. The attacker also bridged 97 × 10^36 + 97 raw units of the custom auxiliary asset ctfhote6ae2a90d1836ef1 from Gonka. The source deposit matches the subsequent NEAR claim, Fmwao…, which minted the HOT representation to 20e6…. In 4wf2…, the attacker deposited 97 × 10^36 auxiliary units into Intents for attack receiver contract dd1…, leaving 97 raw units outside Intents.

HotNear1

This established the large internal balance needed to support the oversized refund requests.

2. Exploit

The first verified exploit, 3k91…, began on 29 September at 16:14:19.280 UTC:

  1. The attacker called HOT’s mt_batch_transfer_call, depositing 97 auxiliary entries of one unit each, plus 10 USDT, into Intents.
  2. Intents successfully credited dd1… before notifying the receiver (attacker) contract.
  3. The receiver returned 97 auxiliary refund requests of 10^36 each, followed by zero requested USDT refund.
  4. The vulnerable resolver limited refunds by the available balance but omitted the current deposit amount. https://github.com/near/intents/blob/35044fd1795b0de9d1ac269c6aa28a0d6a7efdfa/contracts/defuse/src/contract/tokens/mod.rs#L183-L199

The prepared balance therefore allowed enormous refund amounts into the burn event.

HotNear2

Here, balance_left is the receiver’s entire internal balance for that asset, including previous deposits. The calculation checks whether the receiver has sufficient balance, but never limits the refund to deposited-the amount contributed by the current entry. Consequently, an entry depositing only one unit could generate a refund of 10^36 units, provided the receiver’s existing balance covered it.

Each non-zero calculated refund is then appended to the burn event (line 198,199 above):

  1. The resulting event measured 16,495 bytes, specifically
Component Calculation Bytes
97 full token identifiers, each 125 characters 97 × (125 + 2 quotes) + 96 commas 12,415
97 refund amounts, each a quoted 37-digit string 97 × (37 + 2 quotes) + 96 commas 3,879
EVENT_JSON: prefix, metadata, owner ID, memo and remaining JSON punctuation Fixed overhead 201 201
Total 12,415 + 3,879 + 201 16,495

exceeding NEAR’s 16,384-byte log limit by just 11 bytes. Emitting it failed the resolver and rolled back that receipt’s attempted burns.

HotNear3

  1. Failure during event emission reverted the resolver’s preceding balance deductions.

HotNear4

HOT then refunded the entire original batch, including the 10 USDT.

The deposit handler had called self.deposit(...) before scheduling the receiver notification and subsequent mt_resolve_deposit.

HotNear5

These executions occur in separate receipts and failure of a later call does not automatically revert the earlier caller’s changes. (NEAR doc) The Intents credit from the earlier successful receipt survived.

3. Scaling

The net result of the prior sequence is that the attacker retained 10 USDT of internal Intents credit while receiving the original 10-USDT backing back.

HotNear6

That enables two forms of amplification:

  • Reuse: deposit the refunded USDT again, accumulating more internal credit.
  • Compounding: redeem the retained credit into HOT USDT, then use that enlarged balance in a larger batch.

A later call https://nearblocks.io/txns/3mst2uZ32KPuCs7wc8rJqEtCrZqugCy4yDSZ3df8KPm3 deposited 649,984 USDT,requesting redemption of exactly 649,984 USDT back to the sender.

The collected history contains 23 batch calls associated with failed resolvers, with complete retained-credit/backing-refund accounting canonically confirmed for six.

4. Cash out

The attacker subsequently submitted HOT cash-out requests on NEAR specifying the BSC recipient 0x09fd…ad37. Five requests match successful USDT payouts from HOT’s BSC treasury 0x233c…4Cd:

BSC payout time UTC USDT NEAR request BSC payout
Sep 30, 23:54:30 800,000 A1tNAg… 0x9fe58…
Oct 1, 00:24:02 1,200,000 799Tea… 0x038126…
Oct 1, 00:50:42 1,500,000 GJ65… 0x69d1…
Oct 1, 01:46:20 330,000 E4gE… 0x9c10…
Oct 1, 06:08:26 35,000 Avf5… 0x16dd…
Total 3865000

Vulnerability

  1. Credit is committed before the receiver's refund response: The Intents incoming-deposit implementation first calls:
self.deposit(
receiver_id.clone(),
core_token_ids
.clone()
.zip(amounts.iter().map(|amount| amount.0)),
Some("deposit"),
)
.unwrap_or_else(|err| err.panic());

For a notification deposit, it then schedules the receiver call and a later mt_resolve_deposit. The receipt that creates internal credit can succeed before that later resolver fails. The returned promise exposes the later failure to HOT even though the earlier credit already exists.

  1. The vulnerable calculation accepts refunds larger than the current deposit: NEAR's October 1 commit 35044fd…, titled chore: TEMP change that reflects deployed state, reconstructs the refund logic as:
let requested_refund = requested_refund.unwrap_or(*deposited);
let balance_left = receiver.token_balances.amount_for(&token_id);
let refund_amount = balance_left.min(requested_refund);

Source: resolve_deposit_internal.
This calculation respects the available balance but omits the current deposited amount. The loop appends each nonzero refund to a burn event and subtracts it from the receiver balance and internal total supply. It then emits:

MtEvent::MtBurn([burn_event].as_slice().into()).emit();

Those accounting changes are attempted within the resolver receipt. If emission fails, they roll back with it.

  1. possible deployment/source discrepancy: The missing deposited-amount cap was fixed in the public repository on 23 March 2026, at 12:47:07 UTC, in PR #240 / commit 015fa811…, titled "fix: cap notify refunds by the original amounts":
let refund_amount = requested_refund.min(*deposited).min(balance_left);

For the observed one-unit auxiliary entries, this limits each refund to at most one unit regardless of prior balance. It prevents the oversized-number amplification used in this construction. It also restores the central deposit invariant: a refund for the current transfer cannot consume earlier deposits. The October 1 temporary reconstruction commit removes that cap to model deployed behavior. NEAR's October regression-test explanation explicitly says that oversized refund logs caused the callback failure “as happened to the deployed revision.” PR #362 adds regression coverage and audit tooling; Its final production diff does not introduce the original March cap. __These observations support a deployment/source discrepancy. __

Response and Recovery

A post-incident upgrade is visible in FPLaCtd…. Its root transaction at 2 October 20:31:41.711 UTC calls ctl-intents.near.upgrade for intents.near. The controller event identifies release 0.4.4. A successful nested deployment receipt at 20:31:45.442 deploys code and executes state_migrate. Alex Shevchenko publicly stated that the $3.86M was returned in full.

Related Blogs

Heco Bridge Exploit

Heco Bridge Exploit

On 22 November, another major private key compromise affected the Heco Bridge and HTX hot wallets amounting to \$116 million in losses. A malicious actor compromised several wallets belonging to HTX as well as the Heco bridge operator wallet, allowing them to withdraw withdraw assets on Ethereum and TRON. We have also identified a suspicious movement of Bitcoin. This brings the total lost to private key compromises this year to over \$800 million, representing 56% of all funds lost in 2023. This incident is also the fifth largest incident in 2023 and is the largest bridge attack this year.

Bitmart Hot Wallet Compromise

Bitmart Hot Wallet Compromise

Just over a year ago, Bitmart’s hot wallets on Ethereum and BNB Smart Chain (BSC) were compromised leading to $195 million in assets.

Deribit Incident Analysis

Deribit Incident Analysis

On November 2nd, 2022, Deribit Exchange’s hot wallet was compromised. A private key leak may have led to the loss of ~$28m in USDC.