개발자 주석 하나가 초래한 1억 2,800만 달러 규모의 참사: Balancer 반올림 취약점 분석
Balancer의 스마트 컨트랙트 코드 속에 묻혀 있던, 결국 1억 2,800만 달러의 손실을 초래하게 된 함수 바로 위에는 개발자의 주석이 하나 달려 있었습니다. "이 반올림의 영향은 미미할 것으로 예상됩니다." 그들은 틀렸습니다 — 무려 9자리 수나 말이죠.
2025년 11월 3일, 공격자가 Balancer V2의 Composable Stable Pools에서 미세한 반올림 오류를 악용하여 30분 만에 9개 블록체인 네트워크에 걸쳐 자금을 탈취했습니다. 이는 화려한 재진입(reentrancy) 공격이나 유출된 개인 키 때문이 아니었습니다. 그것은 산술 연산의 문제였습니다 — 누구나 볼 수 있는 곳에 숨어 여러 번의 감사를 통과하고, 이를 무기화할 수 있을 만큼 영리한 누군가를 참을성 있게 기다려온 종류의 버그였습니다.
반올림 취약점 공격의 구조
취약한 함수
Balancer V2의 batchSwap 기능을 사용하면 사용자는 단일 트랜잭션에서 여러 토큰 스왑을 실행할 수 있습니다. 내부적으로 _upscaleArray라는 함수는 계산 전에 토큰 잔액을 공통 정밀도로 정규화합니다. 이 함수는 각 토큰의 소수점 자릿수와 내부 비율(internal rate)을 고려하는 *스케일링 팩터(scaling factors)*를 사용합니다.
문제는 무엇이었을까요? 스케일링 팩터가 정수가 아닌 값일 때(토큰 비율이 반영될 때마다 발생), Solidity의 정수 산술 연산은 내림(round down)을 수행합니다. 대부분의 시나리오에서 정밀도 손실은 몇 wei — 즉, 1센트의 아주 작은 부분에 불과합니다. 하지만 유동성 스테이킹 파생상품(LSD)과 같이 밀접하게 연관된 자산을 보유하는 Composable Stable Pools는 StableSwap 불변식(invariant) 계산을 통해 아주 작은 반올림 오류조차 증폭시킵니다.
3단계 공격 전략
공격자의 전략은 단순하면서도 정교했습니다:
-
경계선으로 몰아넣기. 대량의 BPT(Balancer Pool Tokens)를 기초 토큰으로 스왑하여, 한 토큰의 내부 잔액을 8–9 wei라는 임계 범위로 떨어뜨립니다. 이곳은 Solidity의 정수 나눗셈이 최대 정밀도 손실을 발생시키는 정확한 지점입니다.
-
오류 복리화. 경계선에 배치된 토큰을 포함하여 신속하게 미세 스왑(micro-swaps)을 실행합니다. 각 스왑은
_upscaleArray를 트리거하며, EXACT_OUT 작업 중에 내림이 발생합니다. 이 반올림으로 인해 풀의 불변식D가 체계적으로 과소평가되어 BPT 가격이 인위적으로 억제됩니다. -
차액 추출. 억제된 가격으로 BPT를 발행하거나 구매한 다음, 즉시 전체 가치로 기초 자산으로 상환합니다. 이 과정을 반복합니다.
공격자는 생성자(constructor)에서 65회 이상의 미세 스왑을 실행하는 스마트 컨트랙트를 배포하여 정밀도 손실을 치명적인 불변식 조작으로 복리화했습니다. 개별 반올림 오류는 미미했지만, 이것들이 모여 풀의 자금을 고갈시켰습니다.
30분 만에 9개 체인에서 1억 2,800만 달러 증발
이 공격은 Ethereum, Base, Arbitrum, Avalanche, Optimism, Gnosis, Polygon, Berachain, Sonic에서 동시에 발생했습니다. Ethereum이 약 9,900만 달러로 가장 큰 피해를 입었으며, 소규모 체인들은 각각 100만 ~ 1,200만 달러의 손실을 입었습니다.
Hypernative의 자동 모니터링 시스템이 몇 분 만에 공격을 감지했지만, 그때는 이미 피해가 여러 네트워크로 퍼져나가고 있었습니다. 모든 네트워크에 배포된 동일한 취약 코드라는 멀티 체인 특성으로 인해, 단일 체인 사건으로 끝날 수 있었던 일이 DeFi 전체의 위기로 번졌습니다.
체인별 긴급 대응
네트워크별 대응은 탈중앙화 철학의 스펙트럼을 보여주며 극명하게 갈렸습니다:
-
Berachain은 전체 네트워크를 중단하고 긴급 하드포크를 실행하여, 공격을 되돌리고 사용자 예치금 1,280만 달러를 회수했습니다. 이 결정은 논란의 여지가 있었습니다 — 체인이 출시된 지 불과 몇 달 되지 않은 상황에서 사용자 보호와 불변성(immutability) 중 하나를 선택해야 했기 때문입니다.
-
Gnosis Chain은 처음에는 브릿지 활동을 제한하여 체인 간 자금 이동을 방지하는 신중한 접근 방식을 취했습니다. Monerium은 영향을 받은 금고의 130만 EURe를 동결했습니다. 이후 12월 22일, Gnosis는 940만 달러를 회수하기 위해 하드포크를 실행했습니다 — 공격자의 지갑에서 DAO가 제어하는 복구 주소로 자금을 강제로 이동시키기 위해 체인 상태를 재작성한 것입니다.
-
StakeWise DAO는 Balancer의 세이프 하버(Safe Harbor) 프레임워크(2024년 수립된 BIP-726)를 활용하여 화이트햇 복구 작업을 법적으로 승인받았으며, 약 1,900만 달러 상당의 osETH와 170만 달러 상당의 osGNO를 회수했습니다.
총합 약 4,300만 달러가 회수되거나 동결되었으며, 이는 전체 손실액의 약 3분의 1에 해당합니다.
감사의 역설
Balancer 취약점 공격에서 가장 당혹스러운 점은 이 코드가 여러 전문 보안 감사를 통과했다는 사실입니다.
Trail of Bits는 Balancer V2 코드를 감사했으며 실제로 반올림 관련 우려 사항을 식별했었습니다. 2021년 Linear Pools에 대한 검토에서 그들은 반올림 동작을 지적했지만, 그것이 악용 가능한지 확정적으로 판단하지 못했습니다. 그들은 "모든 산술 연산의 반올림 방향이 기대치와 일치하는지" 확인하기 위해 포괄적인 퍼징 테스트(fuzz testing)를 권고했습니다.
이후 2022년 9월 Trail of Bits가 Composable Stable Pools를 검토했을 때, 취약점을 포함하고 있던 정확한 코드인 Stable Math 라이브러리는 명시적으로 감사 범위에서 제외되었습니다.
업계의 위협 지형이 변했습니다. 2021년에는 반올림 및 산술 문제가 중요한 위험 범주로 간주되지 않았습니다. 하지만 2025년까지 반올림 오류는 개인 키 탈취에 이어 DeFi에서 두 번째로 많이 악용되는 취약점이 되었습니다. 감사 표준이 속도를 맞추지 못한 것입니다.
Certora는 Balancer V3에 대해 형식 검증(formal verification)을 수행한 후, 자신들의 V2 검증 속성이 "개별 스왑 간의 관계나 반올림 동작을 제한하지 않았다"고 인정했습니다. 해당 속성들은 높은 수준에서의 지급 능력(solvency)은 보장했지만, 반복적인 작업이 반올림 편향을 통해 체계적으로 가치를 축적할 수 있는 시나리오는 놓쳤습니다.
예외가 아닌 패턴
Balancer 익스플로잇은 갑자기 발생한 것이 아닙니다. 소수점 반올림 정밀도 공격은 DeFi 역사에서 계속해서 증가해 왔습니다.
-
Hundred Finance (2023): 공격자가 WBTC를 기부하여 hWBTC 컨트랙트의 환율을 조작했으며,
redeemUnderlying함수의 반올림 오류를 악용하여 과도한 금액을 인출했습니다. -
Raft Finance (2023): 플래시 론 공격으로 스테이블코인 프로토콜의 정밀도 손실을 악용하여 360만 달러를 탈취했습니다.
-
Compound V2 포크 (진행 중): 낮은
totalSupply값으로 인해 공격자가 기부 공격을 통해 환율을 부풀릴 수 있어, 비어 있거나 거의 비어 있는 대출 풀이 정수 나눗셈 반올림 악용에 취약한 상태로 남아 있습니다. -
Balancer 자체의 2023년 사건: 유사한 산술 가정을 겨냥한 210만 달러 규모의 소규모 반올림 익스플로잇이 발생했으며, 이는 2025년 11월의 치명적인 침해 사고를 예고하는 경고 사격이었습니다.
근본 원인은 항상 동일합니다. Solidity는 네이티브 부동 소수점을 지원하지 않습니다. 모든 나눗셈 연산은 소수점을 버리고(truncate), 모든 곱셈은 오버플로우가 발생할 수 있으며, 모든 정규화 단계에서 잠재적인 오류가 발생합니다. 특히 AMM 불변량(invariant) 계산에서 이러한 오류가 반복적인 연산을 통해 누적되면 결과는 참혹할 수 있습니다.