Threat reportVulnerabilityTL-2026-5075
Balancer V2 ComposableStablePool Rounding/Invariant Manipulation Exploit (Nov 2025)
On 2025-11-03 (~07:40 UTC), Balancer v2 ComposableStablePool instances and Balancer v2 forks were drained via a unidirectional mulDown rounding flaw in _upscale, exposed by _scalingFactors overrides carrying non-unitary exchange rates and chained through batchSwap. Cumulative losses were reported at $120M+ (about $128M in some sources); no CVE was assigned and no attacker identity has been disclosed. First disclosed .
Key facts for Balancer V2 rounding drain
| Identifiers | TL-2026-5075 |
|---|---|
| Also known as | Balancer v2 exploit, Balancer rounding exploit |
| Severity | CRITICAL |
| First disclosed | |
| Exploitation status | Exploited in the wild |
| Affected products | Balancer Balancer v2 ComposableStablePool (incl. v5), LinearPool, MetaStablePool; Third-party Balancer v2 forks Forks inheriting the vulnerable stable-pool code (e.g. Berachain BEX, Beets on Sonic) |
| Weaknesses (CWE) | CWE-682, CWE-190 |
| Malware | Avalanche |
| MITRE ATT&CK techniques | T1190 Exploit Public-Facing Application, T1565.001 Stored Data Manipulation, T1587.004 Exploits, T1588.006 Vulnerabilities, T1657 Financial Theft |
| Motivation | FINANCIAL |
| Target sectors | finance, decentralized-finance, cryptocurrency |
| Target regions | Global |
| Detection rules | 9 (1 shown free) |
| Sources | 7 cited sources |
Detection coverage for Balancer V2 rounding drain
As of 2026-11-02, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-5075 across Splunk SPL, Microsoft KQL and Sigma, covering 19 indicator(s) of compromise. The whole corpus is readable without an account. Every threat comes with one complete detection in Splunk SPL, Microsoft KQL and Sigma, free for everyone; a free account adds daily TL Creds to unlock the rest. Paid plans add a larger daily allowance, correlation and the MCP server. Threadlinqs MCP server · View plans.
Free detection: Balancer v2 BatchSwap GIVEN_OUT Dust Micro-Swap Burst Against Pool BPT (Exploitation)
Behaviour-first search for the Balancer v2 rounding exploit (TL-2026-5075): one batchSwap transaction with 30+ GIVEN_OUT Vault swaps, a leg trading the pool's own BPT and 10+ dust-sized outputs. The exploit used 65 micro-swaps with amounts such as 17 inside one atomic batchSwap (primary Ethereum tx 0x6ed07db1a9fe5c0794d44cd36081d6a6df103fab868cdd75d581e3bd23bc9742). Covers ComposableStablePool, MetaStablePool, LinearPool and forks inheriting the _scalingFactors mulDown pattern.
- Languages: Splunk SPL, Microsoft KQL, Sigma
- ATT&CK: T1190, T1565.001, T1565, T1588.006
- Data sources: splunk index=blockchain sourcetype=evm:balancer:vault_swap, sentinel table BalancerVaultSwaps_CL, sigma product=evm service=balancer_vault
- Severity: critical
- Confidence: high
Splunk SPL
index=blockchain sourcetype="evm:balancer:vault_swap" call_name="batchSwap" swap_kind="GIVEN_OUT" earliest=-24h
| eval pool_addr=lower(substr(pool_id,1,42)), amt_out=tonumber(amount_out)
| eval bpt_leg=if(lower(token_in)==pool_addr OR lower(token_out)==pool_addr,1,0), dust=if(amt_out<=100,1,0)
| stats count AS swap_count sum(bpt_leg) AS bpt_swaps sum(dust) AS dust_swaps dc(pool_id) AS pools dc(amount_out) AS distinct_amounts min(_time) AS first_seen BY chain, tx_hash, tx_from
| where swap_count>=30 AND bpt_swaps>=1 AND dust_swaps>=10
| eval signal="TL-2026-5075 Balancer v2 batchSwap GIVEN_OUT rounding exploit (T1190, T1565.001)", first_seen=strftime(first_seen,"%Y-%m-%d %H:%M:%S")
| table first_seen chain tx_hash tx_from swap_count bpt_swaps dust_swaps distinct_amounts pools signalMicrosoft KQL
BalancerVaultSwaps_CL
| where TimeGenerated > ago(24h)
| where CallName == "batchSwap" and SwapKind == "GIVEN_OUT"
| extend PoolAddr = tolower(substring(PoolId, 0, 42)), AmtOut = todecimal(AmountOut)
| extend BptLeg = iff(tolower(TokenIn) == PoolAddr or tolower(TokenOut) == PoolAddr, 1, 0), Dust = iff(AmtOut <= 100, 1, 0)
| summarize SwapCount = count(), BptSwaps = sum(BptLeg), DustSwaps = sum(Dust), Pools = dcount(PoolId), DistinctAmounts = dcount(AmountOut), FirstSeen = min(TimeGenerated) by Chain, TxHash, TxFrom
| where SwapCount >= 30 and BptSwaps >= 1 and DustSwaps >= 10
| extend Signal = "TL-2026-5075 Balancer v2 batchSwap GIVEN_OUT rounding exploit (T1190, T1565.001)"
| project FirstSeen, Chain, TxHash, TxFrom, SwapCount, BptSwaps, DustSwaps, DistinctAmounts, Pools, SignalSigma
title: Balancer v2 BatchSwap GIVEN_OUT Dust Micro-Swap Burst Against Pool BPT
id: 7c1f3a52-4d8e-4b19-9a62-5e0c8d3b71a4
status: experimental
description: Detects a single Balancer v2 Vault batchSwap transaction containing 30+ GIVEN_OUT swaps, at least one leg trading the pool's own BPT and 10+ dust-sized amounts. Matches the ComposableStablePool mulDown rounding exploit of 2025-11-03 and copycats against forks. Fields are derived by the blockchain ETL enrichment.
references:
- https://www.openzeppelin.com/news/understanding-the-balancer-v2-exploit
- https://research.checkpoint.com/2025/how-an-attacker-drained-128m-from-balancer-through-rounding-error-exploitation/
- https://rekt.news/balancer-rekt2
- https://medium.com/balancer-protocol/nov-3-exploit-post-mortem-51dcbeb6b020
author: AII-Detector — ThreadLinqs Intelligence
date: 2026/11/02
tags:
- attack.initial-access
- attack.t1190
- attack.impact
- attack.t1565
- attack.t1565.001
- attack.resource-development
- attack.t1588.006
- detection.threat-hunting
logsource:
product: evm
service: balancer_vault
detection:
selection_behavior:
call_name: batchSwap
swap_kind: GIVEN_OUT
swap_count|gte: 30
bpt_leg_count|gte: 1
dust_swap_count|gte: 10
selection_known_tx:
tx_hash: ['0x6ed07db1a9fe5c0794d44cd36081d6a6df103fab868cdd75d581e3bd23bc9742', '0xd155207261712c35fa3d472ed1e51bfcd816e616dd4f517fa5959836f5b48569', '0xe4dfc8b8b54eb7e101d59cd9f87f389186b2e8f6e188557ae9dfdbea2b12e703', '0x29135f912d67db38478d0be70b9f2a1fab3b121b74d776f835ac66d6df134ec5', '0x3c9d2d16404a79feed9876a79f168af334726ad3ee1371f581d50ebebfe6b8c6', '0x167993d4cc39771923a6cd11d2d6e73a1b68c7464ea3c76ba41fbd32df7a96da', '0xd7996c8e187b9bd539a04a4f39de4d8c7c1670c601134329937738b4dfa6f8ad', '0x14fb45dd869208edffcb221add152a20292283be172ddb6ccfd2d73e3710b6f4']
condition: selection_behavior or selection_known_tx
falsepositives:
- Protocol-owned rebalancing bots batching many small swaps (rarely GIVEN_OUT on a pool's own BPT)
- Security researchers replaying the public exploit on a fork or testnet mirrored into the index
level: critical
Known false positives:
- Protocol-owned rebalancing or arbitrage bots batching many small swaps through the Vault
- Security researchers replaying the public exploit template on forks or mirrored testnets
Tuning notes: Thresholds (30 swaps, 10 dust swaps, amount_out<=100) come from the reported 65 micro-swap batch with amounts such as 17; lower swap_count to 20 for forks and raise the dust cut-off for 6-decimal tokens. Allowlist known keeper/arbitrage tx_from addresses. Requires an ETL that decodes Vault Swap events per transaction (chain, tx_hash, tx_from, call_name, swap_kind, pool_id, token_in, token_out, amount_in, amount_out); rename fields to your schema.
- Balancer v2 BatchSwap Borrowing Pool BPT Through Internal Balances - Sentinel (Exploitation) · unlock with TL Creds
- Balancer v2 Vault Internal Balance Staging Followed By Withdrawal - Sentinel (Post-Exploitation) · unlock with TL Creds
- Tornado Cash Funded Account Deploys Contract Then Runs Balancer BatchSwap - Sentinel (C2 / Staging Chain) · unlock with TL Creds
- Balancer v2 Fork Vault BatchSwap Dust Burst (Copycat Exploitation) - Sigma · unlock with TL Creds
- Balancer Vault Outflow To Attacker Addresses Or Fresh EOA Multi-Token Drain - Sigma (Post-Exploitation) · unlock with TL Creds
- Balancer v2 Exploit Contract Deployment Followed By BatchSwap Burst - Sigma (C2 / Multi-Chain Infrastructure) · unlock with TL Creds
- Balancer v2 Stable Pool Token Balance Drained To Dust And BPT Rate Suppressed (Post-Exploitation) · unlock with TL Creds
- Balancer v2 Exploit Attacker Infrastructure And Multi-Chain Vault Abuse (C2 / Fund Movement) · unlock with TL Creds
Indicators of compromise for Balancer V2 rounding drain
As of 2026-11-02, Threadlinqs Intelligence tracks 19 indicators of compromise for TL-2026-5075.
How Balancer V2 rounding drain works
Balancer v2 stable-style pools (ComposableStablePool, formerly StablePhantomPool, plus LinearPool and MetaStablePool) share a scaling-helper design in which token amounts are upscaled by _scalingFactors using mulDown. A code comment in the helper states that the impact of this rounding is expected to be minimal, and that there is no rounding error unless _scalingFactors() is overridden. The overrides, which add rate-provider exchange rates on top of decimal normalization, were introduced in MetaStablePool (2021-07-16, commit 059284e), LinearPool (2021-09-01, commit 4e9e70a) and StablePhantomPool/ComposableStablePool (2021-09-20, commit f450760), after the OpenZeppelin audit engagements had ended (OpenZeppelin analysis). With non-unitary scaling factors, truncation becomes material when amounts are tiny relative to the factor. OpenZeppelin's example: an amount of 17 with a scaling factor of 1,058,132,408,689,971,699 upscales to 17 rather than ~17.98.
Exploit mechanics (OpenZeppelin, Check Point, Rekt): the attacker called the Vault's batchSwap, using the transient internal-balances mechanism to borrow BPT inside the batch and defer net settlement. The first phase swapped BPT for pool tokens (e.g. WETH/osETH) to push balances down to very small values. Repeated prime/exploit/reset sequences then executed EXACT_OUT swaps with tiny amounts (e.g. 17 against a vault balance of ~18), so the rounding loss landed on the pool. Check Point counted 65 micro-swaps in a single atomic batchSwap. The compounded precision loss desynchronized the invariant and suppressed the BPT price, and inflated deltas credited most of the pool's assets to the attacker. The invariant protection only held at high liquidity, which is why draining pools to minimal balances was a prerequisite. Balancer's preliminary post-mortem, as reported by Cointelegraph, described rounding in EXACT_OUT swaps on Stable Pools and Composable Stable v5 pools combined with BatchSwap and flash loans, with exploited funds often remaining in the Vault as internal balances before withdrawal.
Impact: Check Point reports $128.64M lost across six chains in under 30 minutes. Rekt reports ~$93.4M in primary losses plus ~$18M from forks and copycats, and ~$38.4M recovered. Chains named across sources include Ethereum, Base, Avalanche, Gnosis, Berachain, Polygon, Sonic, Arbitrum and Optimism. Reported recoveries include StakeWise's multisig recovery of 5,041 osETH and ~13,495 osGNO, and a white-hat rescue of $12.86M on Berachain's BEX. Cointelegraph, citing Cyvers, says the attacker funded operations through Tornado Cash deposits. Per Rekt, copycat exploits against Balancer v2 forks began at 08:39 UTC. Source figures conflict on totals and attribution of recovery amounts. Both are as reported by each source.
Defender relevance: the flaw is logic/arithmetic, not memory corruption, so detection is on-chain and behavioral: Vault batchSwap calls with GIVEN_OUT swaps involving a pool's own BPT, pool token balances driven to very low values, and clusters of near-identical micro-swaps. Monitor any Balancer v2 fork that inherits the _scalingFactors override pattern.
MITRE ATT&CK techniques by tactic:
Initial Access
T1190 Exploit Public-Facing Application
Impact
T1565.001 Stored Data Manipulation; T1657 Financial Theft
Resource Development
Remediation for Balancer V2 rounding drain
Patches
- No CVE or vendor patch identifier is stated in the verified sources; vulnerable pools were paused and remediation was handled via Balancer's post-mortem process
Immediate actions
- Pause affected Balancer v2 pools and activate recovery mode where the pool supports it
- Disable creation of new vulnerable pool instances pending fixes
- Pause or zero collateral parameters for BAL and affected BPT in lending markets (Venus paused BAL borrowing and set LTV to zero per Rekt)
- Monitor and screen the listed attacker addresses and transaction patterns
Workarounds
- Withdraw liquidity from affected ComposableStablePool, LinearPool and MetaStablePool instances where possible
- Fork operators should pause pools that share the vulnerable ScalingHelpers rounding behavior
Longer-term hardening
- Audit all fixed-point scaling and rate-provider code for rounding direction, and make rounding direction-aware (round in the protocol's favor)
- Add invariant and fuzz testing that covers low-liquidity and dust-amount swap states and rounding-direction safety, not only solvency
- Re-audit code added after an audit's scope closed, and review any fork inheriting the _scalingFactors override pattern
- Restrict or rate-limit internal-balance and batchSwap borrowing of pool BPT where feasible
Affected and fixed versions
- Balancer — Balancer v2 ComposableStablePool (incl. v5), LinearPool, MetaStablePool
Vulnerable versions: Pools using the _scalingFactors override with mulDown-based _upscale (MetaStablePool, LinearPool, StablePhantomPool/ComposableStablePool, introduced July-September 2021) - Third-party Balancer v2 forks — Forks inheriting the vulnerable stable-pool code (e.g. Berachain BEX, Beets on Sonic)
Vulnerable versions: Forks inheriting the same scaling helper behavior
Timeline of Balancer V2 rounding drain
- _scalingFactors override introduced in MetaStablePool (commit 059284e), creating the rounding exposure (OpenZeppelin).
- Override added to LinearPool (commit 4e9e70a); added after the audit engagements had completed (OpenZeppelin).
- Override added to StablePhantomPool/ComposableStablePool (commit f450760) (OpenZeppelin).
- First copycat transaction against a Balancer v2 fork at ~08:39 UTC, per Rekt; Berachain, Sonic and Polygon applied chain-level responses.
- StakeWise DAO multisig recovered 5,041 osETH and ~13,495 osGNO roughly 90 minutes after the initial exploit (reported by search-indexed coverage; Cointelegraph cites same amounts).
- Exploit executed at ~07:40 UTC via Vault batchSwap against ComposableStablePools on Ethereum (tx 0x6ed07db1...), then repeated on other chains.
- Balancer published a preliminary post-mortem identifying EXACT_OUT rounding plus BatchSwap in Stable and Composable Stable v5 pools (reported by Cointelegraph).
- OpenZeppelin published its technical analysis of the exploit, citing $120M+ cumulative losses.
Sources cited for Balancer V2 rounding drain
- Understanding the Balancer v2 Exploit (OpenZeppelin) openzeppelin.com · Research · 2025-11-07
- How an Attacker Drained $128M from Balancer Through Rounding Error Exploitation (Check Point Research) Check Point Research · Research
- Nov 3 Exploit Post-Mortem (Balancer, Medium) medium.com · Vendor report
- Balancer exploit transaction 0x6ed07db1... (Etherscan) etherscan.io · Research · 2025-11-03
- Balancer - Rekt II rekt.news · News
- Balancer post-mortem report on $116M hack (Cointelegraph) cointelegraph.com · News · 2025-11-05
- DeFi Protocol Balancer Starts Recovering Funds Stolen in $128 Million Heist (SecurityWeek) SecurityWeek · News
Drafted by the Threadlinqs research pipeline from 7 sources; published ; last updated —.