All incidents

PearlFi NLAMM unchecked multiplication overflow enables underpriced mint-and-drain

Share
Feb 19, 2026 10:41 UTCAttackLoss: 40,335.5 USDTManually checked1 exploit txWindow: Atomic
Estimated Impact
40,335.5 USDT
Label
Attack
Exploit Tx
1
Addresses
3
Attack Window
Atomic
Feb 19, 2026 10:41 UTC → Feb 19, 2026 10:41 UTC

Exploit Transactions

TX 1BSC
0xb4a29409cbd018956746f90d285f427175070c735c36ff3bc2f3c4a4bbaae705
Feb 19, 2026 10:41 UTCExplorer

Victim Addresses

0x5340a7278848ee51d35c30693d6fbff06d1a0d73BSC
0x1903d672c821bdf7cabfde1fb4dc9ebff0494563BSC
0x73a0ba8bac1b6ae00de1e9cf767cdb98075ab92eBSC

Loss Breakdown

40,335.5USDT

Similar Incidents

Root Cause Analysis

PearlFi NLAMM unchecked multiplication overflow enables underpriced mint-and-drain

1. Incident Overview TL;DR

On BSC block 82115373, an unprivileged EOA (0xdbca72816b83a60f5ca7cf93a1420c6e7b215aca) deployed helper contract 0x23e5de4a390702b1ff6da7fd0b0f17b79f8eee1a and executed a single exploit transaction (0xb4a29409cbd018956746f90d285f427175070c735c36ff3bc2f3c4a4bbaae705).

The core root cause is unchecked arithmetic inside NLAMM buy at incident implementation 0x1903d672c821bdf7cabfde1fb4dc9ebff0494563 (behind proxy 0x5340a7278848ee51d35c30693d6fbff06d1a0d73). Attacker-controlled amount values around 1e60 to 1e63 are multiplied by currentPrice and 1e18 under unchecked, so both payment and mint amounts wrap modulo 2^256 instead of reverting. The attacker pays tiny wrapped USDT amounts, receives huge wrapped token mints, then dumps those mints through public DexFactory routes to drain USDT pools.

Observed outcome: attacker EOA receives 40341541995032481116169 USDT in the same transaction, while five USDT pools are heavily depleted.

2. Key Background

PearlFi’s NLAMM allows public buy(tokenAddress, tokenIndex, amount) calls. During the incident, that path performed economic multiplications in an unchecked block.

Dex routing is also public via DexFactory proxy 0x73a0ba8bac1b6ae00de1e9cf767cdb98075ab92e (implementation 0x55ab5af53852bfc5f933ab4d7441b4b6c68ea52e). Once large token balances are minted, normal AMM swap logic can convert them into USDT and drain pair reserves.

This is ACT because no privileged roles or private data are required: the exploit uses public/external entrypoints, public chain state, and standard transaction submission.

Pre-state (sigma_B) used by the analysis is BSC at block 82115373, reconstructable from:

  • seed metadata for tx identity and block context
  • verbose execution trace for call-level behavior
  • tx balance diffs for native and ERC20 deltas
  • verified source for NLAMM and DexFactory implementations

Additional protocol facts used:

  • registry verification enables privileged token operations (mint/verifiedTransfer), but user entrypoints (buy, swaps) remain public
  • constant-product pool math means overflow-minted token supply can be monetized by selling into existing USDT liquidity

3. Vulnerability Analysis & Root Cause Summary

Root cause category: ATTACK.

The violated invariant is: payment and minted output for buy must be overflow-safe functions of requested amount; overflow must revert instead of wrap. In incident code, the first safety break occurs when NLAMM computes amount * currentPrice and amount * 1e18 inside unchecked. Because amount is attacker-controlled and unbounded, arithmetic wraps modulo 2^256. As a result, charged USDT is far lower than intended while minted token output is extremely large.

The trace confirms this behavior repeatedly across five buy legs with currentPrice around 1e14 to 1e16 and amount around 1e60 to 1e63. Wrapped products match traced debits/mints exactly. The attacker then swaps overflow-minted tokens through public DexFactory pairs to extract USDT.

Vulnerable components:

  • NLAMM buy path in incident implementation 0x1903d672c821bdf7cabfde1fb4dc9ebff0494563
  • DexFactory swap routing (0x55ab5af53852bfc5f933ab4d7441b4b6c68ea52e) and DexLibrary output math

Exploit preconditions:

  • token listing exists and is publicly purchasable through NLAMM buy
  • attacker can choose amount values that overflow amount * currentPrice and amount * 1e18
  • liquid swap route from minted token outputs to USDT is available

Security principles violated:

  • avoid unchecked arithmetic on attacker-controlled economic inputs without strict bounds
  • preserve overflow-safe accounting before transfers and mint operations
  • fail closed on arithmetic overflow in pricing and mint logic

4. Detailed Root Cause Analysis

4.1 Code-level breakpoint

Snippet from the incident NLAMM implementation (buy):

function buy(address tokenAddress, uint256 tokenIndex, uint256 amount) external {
    unchecked {
        INLAMM.Token storage tokenRef = _checkTokenExists(tokenAddress, tokenIndex);
        (uint256 basePrice, uint256 targetPrice, uint256 currentPrice) = _getPrices(tokenRef);

        TransferHelper.safeTransferFrom({
            token: _stableCoin,
            from: msg.sender,
            to: address(this),
            value: amount * currentPrice,
            infAllowance: false
        });

        // ...

        if (tokenAddress == _pearl || tokenAddress == _blackPearl) {
            TransferHelper.safeTransfer({ token: tokenAddress, to: msg.sender, value: amount * E18 });
        } else {
            TransferHelper.mintERC20({ token: tokenAddress, to: msg.sender, value: amount * E18 });
        }
    }
}

This unchecked multiplication is the deterministic breakpoint.

4.2 Trace evidence of wrapped payment + wrapped mint

From the exploit trace (first leg):

NLAMM::getPrices(0x26C970..., 0)
  <- [Return] ... currentPrice: 15013380795249012

NLAMM::buy(0x26C970..., 0, 7712592574349318455520271942948603129480035752544334327373265)
  BEP20USDT::transferFrom(..., value: 5319060416824244)
  0x26C970...::mint(..., value: 70314684686449557564586932375201211164216764612057100769064455477733443764224)

The same pattern appears on all five legs. Independent recomputation confirms exact modulo-2^256 equality for both payment and mint formulas:

leg 1: (amount*price)%2^256 == charged  -> True ; (amount*1e18)%2^256 == minted -> True
leg 2: (amount*price)%2^256 == charged  -> True ; (amount*1e18)%2^256 == minted -> True
leg 3: (amount*price)%2^256 == charged  -> True ; (amount*1e18)%2^256 == minted -> True
leg 4: (amount*price)%2^256 == charged  -> True ; (amount*1e18)%2^256 == minted -> True
leg 5: (amount*price)%2^256 == charged  -> True ; (amount*1e18)%2^256 == minted -> True

4.3 Conversion to USDT and payout

After overflow mints, attacker helper swaps into USDT through DexFactory pairs. Trace shows large swap outputs and final transfer to attacker EOA:

... Swap(... tokenOut: USDT, amountOut: 7805558224390563581443)
... Swap(... tokenOut: USDT, amountOut: 8337144257673105534613)
... Swap(... tokenOut: USDT, amountOut: 9541691613786665270666)
... Swap(... tokenOut: USDT, amountOut: 6468134888472375307607)
... Swap(... tokenOut: USDT, amountOut: 8182972560290464373034)

BEP20USDT::transfer(0xDbCa72816b83a60f5ca7cF93a1420C6e7b215aca, 40341541995032481116169)

5. Adversary Flow Analysis

Adversary strategy summary: single-transaction multi-leg overflow mint-and-dump extraction.

Adversary-related accounts:

  • EOA: 0xdbca72816b83a60f5ca7cf93a1420c6e7b215aca (origin sender, final USDT recipient)
  • Helper contract: 0x23e5de4a390702b1ff6da7fd0b0f17b79f8eee1a (created and used in the exploit transaction)

Victim/protocol components involved:

  • NLAMM proxy: 0x5340a7278848ee51d35c30693d6fbff06d1a0d73
  • NLAMM incident implementation: 0x1903d672c821bdf7cabfde1fb4dc9ebff0494563
  • DexFactory proxy: 0x73a0ba8bac1b6ae00de1e9cf767cdb98075ab92e

Execution stages:

  1. Initial funding and setup: attacker sends 0.01 BNB in the create transaction; helper swaps BNB->USDT and approves NLAMM.
  2. Overflowed buy execution: helper performs five buy calls with huge amount, triggering wrapped charge/mint math.
  3. Swap and realization: helper swaps minted tokens through five USDT pairs and transfers resulting USDT to attacker EOA.

Sequence details from ACT definition:

  • sequence index 1, chain 56, tx 0xb4a29409cbd018956746f90d285f427175070c735c36ff3bc2f3c4a4bbaae705
  • type: adversary-crafted create transaction
  • inclusion feasibility: unprivileged EOA can submit the same public call path
  • note: exploit is fully realized in one transaction

ACT feasibility statement: the full path is callable by any unprivileged actor and does not require owner roles, compromised keys, or private orderflow.

6. Impact & Losses

Measured USDT depletion from five pools (balance diffs):

  • 0x9849e6828022e8b5161cd5c70f4bf38eaf78cfde: -7805558224390563581443
  • 0x3119b2f98693a333394c2e68c0b31dcde7183dae: -8337144257673105534613
  • 0xb38d61552658bacdb382bb3074c104e0a2060ed0: -9541691613786665270666
  • 0xf5784cbdd3d64dbdf882fd9f5b89109793e9f7e6: -6468134888472375307607
  • 0x9095d1083a19be8e390536e9acaf5d4080ce87aa: -8182972560290464373034

Total drained from those five pools: 40335501544613174067363 USDT units.

Attacker EOA USDT delta: +40341541995032481116169.

Native token delta shows attacker paid transaction costs (-10145295420868144 wei including 0.01 BNB tx value and gas), while net USDT extraction remained strongly positive.

Profit predicate context:

  • reference asset: USDT (18 decimals on BSC)
  • attacker USDT before: 0
  • attacker USDT after: 40341541995032481116169
  • tx fee + funding outflow: 0.000145295420868144 BNB gas plus 0.01 BNB value
  • same-tx conversion anchor: 0.01 WBNB -> 6050459719766201456 USDT equivalent
  • net interpretation: approximately +40335.40 USDT after BNB-cost equivalence

Impact statement from analysis: five USDT pools were drained from multi-thousand reserves to near-dust levels in one transaction, with attacker EOA realizing 40341.541995032481116169 USDT inflow.

7. References

Root-cause evidence references:

  • [1] Seed metadata and tx identity: /workspace/session/artifacts/collector/seed/56/0xb4a29409cbd018956746f90d285f427175070c735c36ff3bc2f3c4a4bbaae705/metadata.json
  • [2] Verbose tx trace: /workspace/session/artifacts/collector/iter_1/tx/56/0xb4a29409cbd018956746f90d285f427175070c735c36ff3bc2f3c4a4bbaae705/trace.cast.log
  • [3] Balance diffs: /workspace/session/artifacts/collector/iter_1/tx/56/0xb4a29409cbd018956746f90d285f427175070c735c36ff3bc2f3c4a4bbaae705/balance_diff.json
  • [4] NLAMM incident implementation source: /workspace/session/artifacts/collector/iter_1/contract/56/0x1903d672c821bdf7cabfde1fb4dc9ebff0494563/source/forge_clone/src/nlamm/NLAMM.sol
  • [5] DexFactory source: /workspace/session/artifacts/collector/iter_1/contract/56/0x55ab5af53852bfc5f933ab4d7441b4b6c68ea52e/source/forge_clone/src/dex/DexFactory.sol
  • [6] DexLibrary source: /workspace/session/artifacts/collector/iter_1/contract/56/0x55ab5af53852bfc5f933ab4d7441b4b6c68ea52e/source/forge_clone/src/dex/libraries/DexLibrary.sol

All relevant transactions in scope:

  • seed: 0xb4a29409cbd018956746f90d285f427175070c735c36ff3bc2f3c4a4bbaae705
  • related: 0x886f130770173ab7e6a2dd12dc35656408d0983528382a00b78be2986117447e
  • related: 0x8731f3d5a2e9d88ad671d3a162420434d9476ba3537b87a46e78a49cc58eb8f9