Skip to content

Latest commit

 

History

History
214 lines (155 loc) · 8.75 KB

File metadata and controls

214 lines (155 loc) · 8.75 KB

Retroactive Analysis: $128M Balancer V2 Exploit

Disclaimer: This is a retroactive, hypothetical analysis. Argus was not running at the time of this exploit. Signal names and detection outputs shown below represent what the current pipeline would produce — some signals (e.g., LargeCalldataSize) are planned but not yet implemented in the codebase.

Date: November 3, 2025 Loss: $128.64M across 6 chains (Ethereum: $100M) Root Cause: Rounding error in _upscaleArray compounded via batchSwap Attacker: 0x506D1f9EFe24f0d47853aDca907EB8d89AE03207 Attack Contract: 0x54B53503c0e2173Df29f8da735fBd45Ee8aBa30d


What Happened

At 7:48 AM UTC on November 3, 2025, an attacker deployed a contract that exploited a rounding error in Balancer V2's ComposableStablePool. The entire attack completed in under 30 minutes.

The Vulnerability

Balancer's _upscaleArray function rounds token amounts during internal swaps. A single swap produces negligible precision loss. But the attacker discovered that within a single batchSwap transaction containing 65 operations, these losses compound dramatically.

The 3-Stage Attack

Stage 1: Price Suppression
  Swap large BPT → underlying tokens
  Push one token's balance to 8-9 wei (rounding error maximized)

Stage 2: Exploit Rounding
  Execute small swaps at the boundary threshold
  Each swap extracts a tiny profit from precision loss

Stage 3: Profit Extraction
  Mint/buy BPT at suppressed price
  Redeem BPT for underlying assets at full value
  Repeat across multiple pools

The attacker executed this cycle rapidly across Ethereum, Base, Polygon, and Arbitrum.


How Argus Would Have Detected This

Detection Point 1: Sentinel Pre-Filter (before block inclusion)

Argus monitors the mempool for suspicious transactions. The attack transaction would trigger 3 pre-filter signals:

Signal: UnusualGasPattern
  Gas limit: ~3,000,000 (batchSwap with 65 operations)
  Threshold: top 0.1% of gas usage

Signal: KnownContractInteraction
  Target: Balancer Vault (0xBA12222222228d8Ba445958a75a0704d566BF2C8)
  Label: "Balancer V2 Vault — high-value DeFi protocol"

Signal: MultipleErc20Transfers  [implemented]
  65 batchSwap operations generate many ERC-20 Transfer events
  Threshold: > min_erc20_transfers (configurable)

Pre-filter verdict: Score 0.65 → Promoted to Deep Analysis.

Detection Point 2: Sentinel Deep Analyzer (opcode replay)

The Deep Analyzer replays the transaction through the EVM and examines opcode-level behavior:

Deep Analysis Results:
  ─────────────────────────────────────────
  Total opcode steps:           ~850,000
  CALL opcodes:                 197
  STATICCALL opcodes:           312
  SSTORE opcodes:               89
  Unique addresses touched:     14

  Pattern: PriceManipulation
    Evidence: 65 sequential swap operations in single tx
    Evidence: Token balance driven to < 10 wei (boundary value)
    Evidence: BPT price changed > 40% within transaction
    Confidence: 82%

  Pattern: FlashLoan  [implemented — src/autopsy/types.rs]
    Evidence: Large value movement with same-block profit extraction
    Evidence: Net profit extracted: ~$2.1M per cycle
    Confidence: 71%

  Alert Priority: CRITICAL
  Score: 0.92

Detection Point 3: Auto-Pause Circuit Breaker (optional, disabled by default)

Warning: Auto-pause is disabled by default. Enabling it on a validator node risks slashing penalties from missed attestations. See operational risk.

On a Critical alert (score > 0.85), if auto-pause is enabled, it would:

  1. Halt block processing — Prevent the node from propagating the block
  2. Emit webhook alerts — Slack/Discord/PagerDuty notification within seconds
  3. Log to JSONL — Immutable audit trail
[SENTINEL] CRITICAL ALERT — Auto-pause triggered (if enabled)
  Block:    #21040XXX
  TX:       0x6ed07db...
  Score:    0.92
  Pattern:  PriceManipulation (82%), FlashLoan (71%)
  Action:   Block processing HALTED (requires auto_pause.enabled = true)
  Webhook:  Sent to Slack (#security-alerts)

Detection Point 4: Autopsy Lab (post-incident)

After the attack, Argus's Autopsy Lab generates a forensic report:

═══════════════════════════════════════════════════
  SMART CONTRACT AUTOPSY REPORT
═══════════════════════════════════════════════════

Transaction: 0x6ed07db...
Block:       #21040XXX
Gas Used:    2,847,392

ATTACK SUMMARY
  Classification: Price Oracle Manipulation via Rounding Exploit
  Confidence:     82%
  Estimated Loss: $2,100,000 (this transaction)

ATTACK TIMELINE
  Step    0-   200: Contract deployment + initialization
  Step  200- 2,400: Stage 1 — Large BPT→token swaps (price suppression)
  Step 2,400-45,000: Stage 2 — 65 batchSwap operations (rounding extraction)
  Step 45,000-50,000: Stage 3 — BPT mint at suppressed price + redemption

FUND FLOW
  Attacker (0x506D...) → Attack Contract (0x54B5...)
    └── Balancer Vault (0xBA12...) → Attacker
        ├── 1,847 WETH ($4.2M)
        ├── 2,100,000 USDC
        └── 890,000 DAI

EVIDENCE
  1. Token balance reduced to 8 wei at step #2,847 (rounding boundary)
  2. 65 sequential batchSwap calls in single transaction
  3. BPT internal price deviation: -43.7% during execution
  4. All profit extracted to attacker address within same block

SUGGESTED MITIGATIONS
  - Round UP for outgoing token calculations (_downscaleArray)
  - Add minimum balance threshold check (reject < 1000 wei)
  - Implement per-block swap frequency limits on batchSwap

Timeline: Argus vs What Actually Happened

Time What Happened What Argus Would Have Done
7:47 AM Attack TX enters mempool Mempool pre-filter flags TX (score 0.65)
7:48 AM TX included in block Deep Analyzer: CRITICAL (score 0.92)
7:48 AM Auto-pause halts block propagation (if enabled)
7:48 AM Webhook sent to security team
7:49-8:15 AM Attacker repeats on 5 more chains Node operators on other chains alerted
8:30 AM Community notices unusual transfers Already detected 42 minutes earlier
10:00 AM Balancer confirms exploit Autopsy report already generated

Key insight: The 42-minute detection gap between the attack and community awareness is where $128M was lost. Argus's pre-filter would likely have flagged the transaction upon block inclusion due to unusual gas + ERC-20 transfer count.


Why Existing Tools Missed This

Tool Why It Missed
Slither/Mythril Static analysis — the rounding error is only exploitable with specific pool states. Couldn't detect runtime behavior.
Forta bots Detected transfers after the fact, but no opcode-level analysis of the batchSwap internals.
Tenderly Transaction simulation available, but no automated pattern classification or circuit breaker.
Argus Would likely have flagged it — pre-filter on gas + ERC-20 transfers, deep analyzer on swap patterns. Auto-pause available but disabled by default.

Reproduce With Argus

You can run a similar detection scenario locally:

git clone https://github.com/tokamak-network/Argus.git
cd Argus

# Run the reentrancy detection demo (similar multi-stage attack pattern)
cargo run --example reentrancy_demo

# Run the full Sentinel pipeline demo
cargo run --example sentinel_realtime_demo

The Sentinel demo shows the same detection pipeline that would catch Balancer-style attacks: pre-filter → deep analysis → alert dispatch → auto-pause.


References


This analysis was produced using Argus by Tokamak Network.