Back to Blog

#4 GMX 사고: 크로스 컨트랙트 재진입 공격으로 4년된 보안 가드 우회

Code Auditing
February 10, 2026
7 min read

2025년 7월 9일, 탈중앙화 영구 포지션 플랫폼 GMX가 Arbitrum 네트워크의 V1 컨트랙트를 대상으로 한 익스플로잇 [1, 2]을 겪었으며, 약 4,200만 달러의 손실이 발생했습니다. 공격자는 크로스 컨트랙트 재진입 취약점을 악용하여 GLP 가격을 조작한 뒤, 왜곡된 가격을 이용해 GMX V1의 유동성 풀에서 기초 자산을 탈취했습니다.

배경

GMX V1 [3]은 Arbitrum에 배포된 탈중앙화 영구 포지션 거래 플랫폼입니다. 사용자는 허가 없이 비수탁 방식으로 다양한 암호화폐 자산에 대해 레버리지를 사용한 영구 계약을 거래할 수 있습니다. GMX V1은 단일 다중 자산 풀 설계를 따르며, 지원되는 모든 자산의 유동성이 통합된 Vault 시스템에 집계됩니다.

GMX의 포지션 관리

GMX의 포지션 관리는 두 단계로 이루어집니다. 구체적으로, 사용자는 OrderBook 또는 PositionRouter 컨트랙트와 상호작용하여 증가/감소 주문을 생성합니다. 그런 다음 권한이 부여된 키퍼(keeper) 계정이 사용자의 주문을 실행하며, 이 과정에서 ShortTracker 컨트랙트의 글로벌 숏 데이터와 Vault 컨트랙트의 해당 상태가 업데이트됩니다. 아래 두 그림은 GMX에서 포지션을 관리하기 위한 두 가지 실행 경로(orderbook-execution 경로와 router-execution 경로)를 보여줍니다. 이번 사건에서 공격자는 두 경로를 모두 사용하여 글로벌 숏 데이터를 조작하고 수익을 실현했습니다.

Orderbook-execution 경로

Router-execution 경로

GMX Vault

GMX의 Vault 컨트랙트는 사용자의 포지션 및 자산 관리(예: 손익 확정)를 담당합니다. 악의적인 상호작용을 방지하기 위해, Vault 컨트랙트는 "레버리지 창"이 열려 있을 때(즉, Vault 컨트랙트의 변수 isLeverageEnabledTimelock.enableLeverage() 함수를 통해 true로 설정된 경우)에만 접근할 수 있습니다. 이 유효성 검사는 주문 실행이 고정된 경로(orderbook-executionrouter-execution)를 따르도록 강제합니다.

GMX Short Tracker

ShortTracker 컨트랙트는 주문 실행 중 글로벌 숏 데이터(예: 변수 globalShortAveragePrice)를 추적하고 업데이트하는 역할을 합니다. orderbook-executionrouter-execution 경로에 따라, ShortTracker 컨트랙트의 updateGlobalShortData() 함수는 최신 글로벌 숏 데이터를 동기화하기 위해 사용자 주문 실행 전에 호출됩니다. 이 단계는 사용자 포지션에 대한 올바른 손익 실현을 보장합니다.

WETH 포지션 감소

다른 주문과 달리, orderbook-execution 경로를 통해 WETH 포지션을 감소시키면 OrderBook 컨트랙트의 _transferOutETH() 함수가 호출되어 WETH 토큰을 인출하고 네이티브 ETH 토큰을 사용자에게 전송합니다. 수신자 _receiver가 컨트랙트인 경우, sendValue()가 컨트랙트의 fallback() 함수를 트리거하여 잠재적인 재진입 취약점을 유발할 수 있습니다. 이번 사건에서 공격자는 이 재진입 취약점을 반복적으로 악용하여 상당한 수익을 탈취했습니다.

GLP 토큰

GLP(GMX Liquidity Provider) 토큰은 Vault 컨트랙트 내 다양한 자산에 대한 통합 지분을 나타냅니다. 사용자는 GLP를 민팅하고 소각함으로써 자산을 제공하고 환매할 수 있습니다.

GLP 가격은 다음 방정식으로 계산할 수 있습니다:

GLPPrice=AUMGLPTotalSupply\text{GLPPrice}= \frac{\text{AUM}}{\text{GLPTotalSupply}}

AUM=i=asset[0]assets(ΔGlobalShort[i]+AUMOther[i])\text{AUM} = \sum^{assets}_{i = asset[0]}(\Delta_{\text{GlobalShort[i]}} + \text{AUM}_{\text{Other[i]}})

ΔGlobalShort[i]=globalShortSize×(AssetMarketPriceglobalShortAveragePrice)globalShortAveragePrice\Delta_{\text{GlobalShort[i]}} = \frac{ \text{globalShortSize} \times (\text{AssetMarketPrice} - \text{globalShortAveragePrice} ) }{ \text{globalShortAveragePrice} }

여기서:

  • GLPTotalSupply는 GLP 토큰의 총 공급량을 나타냅니다.
  • AUM은 다음 두 가지 구성 요소로 이루어집니다.
    • ΔGlobalShort\Delta_{\text{GlobalShort}}는 모든 숏 포지션의 미실현 손익(uPnL)을 나타냅니다.
    • AUMOther\text{AUM}_{\text{Other}}는 LP가 제공한 유동성과 모든 롱 포지션의 미실현 uPnL을 나타냅니다. 이 항목은 수익 실현 이전 사건 전반에 걸쳐 거의 변하지 않았습니다.
  • AssetMarketPrice는 기초 자산의 시장 가격(USD 기준)입니다.
  • globalShortSize는 모든 숏 포지션의 합계(USD 기준)입니다.
  • globalShortAveragePrice는 집계된 글로벌 숏 포지션의 평균 진입 가격입니다.

이번 사건에서 공격자는 globalShortAveragePrice를 왜곡하여 GLP 가격을 조작하고 수익을 탈취했습니다.

취약점 분석

근본 원인은 OrderBook 컨트랙트의 크로스 컨트랙트 재진입 취약점입니다. 배경에서 설명한 것처럼, orderbook-execution 경로를 통해 WETH 포지션을 감소시키면 _transferOutETH()를 통해 수신자에게 저수준 폴백 호출이 트리거됩니다. 이 함수에는 nonReentrant 수정자가 적용되어 있지만, 이 가드는 OrderBook 컨트랙트 내의 재진입만 방지할 뿐 Vault에 대한 크로스 컨트랙트 호출은 방지하지 못합니다.

정상적인 운영 하에서, VaultincreasePosition()PositionRouterPositionManager를 통해서만 호출될 수 있으며, 이들은 각 포지션 변경 전에 ShortTracker를 호출하여 globalShortAveragePrice를 업데이트합니다. 공격자는 악의적인 컨트랙트를 수신자로 지정한 주문을 생성했고, 폴백 호출 중에 PositionRouter/PositionManager 및 관련 ShortTracker 업데이트를 우회하여 VaultincreasePosition()을 직접 호출했습니다. 공격자는 globalShortAveragePrice를 업데이트하지 않은 채 숏 포지션을 반복적으로 열고 닫음으로써 해당 변수를 점진적으로 왜곡했습니다. 왜곡된 값은 GLP 가격을 부풀렸고, 공격자는 GLP를 민팅하고 환매하여 수익을 탈취할 수 있었습니다.

공격 분석

공격자는 글로벌 숏 데이터를 조작하고 수익을 실현하는 일련의 트랜잭션을 실행했습니다. 구체적으로, 이번 사건은 세 단계로 나눌 수 있습니다: 준비, 가격 조작, 수익 실현. 관련된 모든 트랜잭션은 아래 표에 나열되어 있습니다.

Tx 번호 단계 설명 트랜잭션 시간 (UTC)
1 준비 공격 컨트랙트 배포 0xa4ece5...8cd4c93f Jul-09-2025 12:16:32 PM
2 WETH 롱 증가 주문 생성 0x0b8cd6...e90a4712 Jul-09-2025 12:22:28 PM
3 WETH 롱 증가 주문 실행 0x28a000...7bf0beef Jul-09-2025 12:23:23 PM
4 WETH 롱 감소 주문 생성 0x20abfe...decc49af Jul-09-2025 12:24:56 PM
5 가격 조작 1 WETH 롱 감소 주문 실행 0x1f00da...6a4a7353 Jul-09-2025 12:25:37 PM
6 WBTC 숏 감소 주문 실행 0x222cda…c994464e Jul-09-2025 12:25:43 PM
7 가격 조작 2 Tx 5와 동일 0xc9a469...221293c2 Jul-09-2025 12:26:25 PM
8 Tx 6과 동일 0x1cbf25...d853943a Jul-09-2025 12:26:30 PM
9 가격 조작 3 Tx 5와 동일 0xb58415...3b4cfb0b Jul-09-2025 12:27:22 PM
10 Tx 6과 동일 0x5a37ff...cb59c3b7 Jul-09-2025 12:27:28 PM
11 가격 조작 4 Tx 5와 동일 0xff6fe6...377bf108 Jul-09-2025 12:28:13 PM
12 Tx 6과 동일 0xbd65d6...e0187be6 Jul-09-2025 12:28:18 PM
13 가격 조작 5 Tx 5와 동일 0x105273...19fcdec6 Jul-09-2025 12:29:12 PM
14 Tx 6과 동일 0x0cdbac...84339fcc Jul-09-2025 12:29:17 PM
15 수익 실현 수익 실현 0x03182d....a32626ef Jul-09-2025 12:30:11 PM
16 환불 공격자에게 메시지 전송 0x92a39e...89547380 Jul-09-2025 02:04:19 PM
17 GMX 프로토콜에 응답 0x1d806c...919feac0 Jul-11-2025 06:29:00 AM
18 공격자에게 응답 0x9c4ca9...39fa27fc Jul-11-2025 07:42:17 AM
19 환불 0x62b845...99211841 Jul-11-2025 08:04:34 AM
20 환불 0x255d0a...9321b3 Jul-11-2025 08:08:27 AM
21 환불 0xceafc3...a6313b22 Jul-11-2025 10:17:23 AM

준비 단계

  1. (Tx 1) 공격자는 주문 실행 중 자산 수신자로 사용될 공격 컨트랙트를 배포했습니다. 공격 컨트랙트에는 악의적인 fallback() 함수가 포함되어 있었습니다.

  2. (Tx 2) 공격자는 OrderBook 컨트랙트에서 공격 컨트랙트를 위한 WETH 롱 증가 주문을 생성했습니다.

  3. (Tx 3) 키퍼가 공격자의 증가 주문(2단계에서 생성)을 실행하여 공격 컨트랙트를 위한 WETH 롱 포지션을 개설했습니다. (Tx 3).

  4. (Tx 4) 공격자는 OrderBook 컨트랙트에서 공격 컨트랙트를 위한 WETH 롱 감소 주문을 생성했습니다.

조작 단계

  1. (Tx 5) 키퍼가 orderbook-execution 경로를 통해 공격 컨트랙트의 WETH 롱 감소 주문(4단계에서 생성)을 실행했습니다. 실행 경로는 _transferOutETH()를 호출하여 공격 컨트랙트의 악의적인 fallback() 함수를 트리거했습니다.

    fallback()이 "레버리지 창"이 열린 동안 호출되었기 때문에, 공격 컨트랙트는 globalShortAveragePrice를 업데이트하지 않고 Vault 컨트랙트와 직접 상호작용하여 WBTC 숏 포지션을 개설했으며(increasePosition() 호출), 이후 WBTC 숏 감소/종료 주문을 생성했습니다.

  2. (Tx 6) 키퍼가 router-execution 경로를 통해 WBTC 숏 감소 주문(5단계에서 생성)을 실행했습니다. 이 실행은 또한 PositionRouter 컨트랙트의 폴백 메커니즘을 통해 WETH 롱 감소 주문을 생성했습니다.

    WBTC 숏 포지션이 globalShortAveragePrice를 업데이트하지 않고 개설되었기 때문에, 해당 변수를 업데이트하면서 포지션을 종료하면 globalShortAveragePrice가 예기치 않게 하락했습니다.

  3. (Tx 7-14) 공격자는 5-6단계를 4회 반복했습니다. 그 결과, globalShortAveragePrice1.08e35에서 1.9e33으로 왜곡되었습니다.

수익 실현 단계

  1. (Tx 15) 키퍼가 orderbook-execution 경로를 통해 WETH 롱 감소 주문(Tx 14에서 생성)을 실행했습니다. 이 실행은 OrderBook 컨트랙트의 재진입 취약점으로 인해 공격 컨트랙트의 수익 실현 로직을 트리거했습니다.

    1. 폴백 호출에서 공격 컨트랙트는 먼저 7,538,567e18 USDC의 플래시 론을 빌렸습니다.

    2. 공격 컨트랙트는 mintAndStakeGlp()를 호출하여 6,000,000e18 USDC를 사용해 4,129,578e18 GLP를 민팅했습니다.

    3. 공격 컨트랙트는 Vault.increasePosition()을 호출하여 나머지 1,538,567e18 USDC로 WBTC 숏 포지션을 개설했습니다. WBTC의 글로벌 숏 데이터가 극도로 왜곡되어 있었기 때문에, 주문 실행 시 AUM이 크게 증폭되어 GLP 가격이 급격히 상승했습니다.

    4. 공격 컨트랙트는 unstakeAndRedeemGlp()를 호출하여 증폭된 가격으로 GLP를 환매하여 Vault 컨트랙트의 여러 자산을 획득했습니다.

    5. 공격 컨트랙트는 Vault.decreasePosition()을 호출하여 WBTC 숏 포지션을 종료했습니다.

    6. 공격 컨트랙트는 8.b-8.e 단계를 4회 반복하여 Vault 컨트랙트의 모든 자산을 고갈시켰습니다.

    7. 공격 컨트랙트는 약 4,200만 달러의 수익을 남기고 플래시 론을 상환했습니다.

환불

공격자와의 협상(Tx 16-18)을 통해, 공격자는 최종적으로 10% 바운티를 수락하고 나머지 탈취한 자산을 반환했습니다(Tx 19-21).

요약

이번 사건은 Arbitrum의 GMX V1을 대상으로 한 다단계 익스플로잇으로, 약 4,200만 달러의 손실이 발생한 것으로 추정됩니다. 공격자는 OrderBook 컨트랙트의 재진입 취약점을 악용하여 globalShortAveragePrice 변수를 왜곡하고 GLP 가격을 부풀렸습니다. 조작된 가격을 활용하여 공격자는 상당한 양의 자산을 탈취했습니다.

주요 교훈:

  • 크로스 컨트랙트 재진입: 단일 컨트랙트의 nonReentrant 수정자는 동일 시스템 내 다른 컨트랙트로의 재진입을 방지하지 못합니다. 임시 플래그(예: "레버리지 창")에 의존하는 접근 제어 메커니즘은 플래그가 재설정되기 전에 외부 호출이 발생할 경우 우회될 수 있습니다.
  • 운영 보안: 이번 공격자는 총 15개의 트랜잭션을 실행하여 세 가지 뚜렷한 단계로 프로토콜을 익스플로잇했습니다. 이번 사건은 실시간 모니터링, 신속한 경보 및 효과적인 완화 플레이북의 중요성을 강조합니다.

참고 자료

  1. https://x.com/GMX_IO/status/1942955807756165574
  2. https://x.com/GMX_IO/status/1943336664102756471
  3. GMX V1

BlockSec 소개

BlockSec은 풀스택 블록체인 보안 및 암호화폐 컴플라이언스 제공업체입니다. 저희는 고객이 코드 감사(스마트 컨트랙트, 블록체인 및 지갑 포함), 실시간 공격 차단, 사건 분석, 불법 자금 추적, AML/CFT 의무 이행을 프로토콜 및 플랫폼의 전체 생애주기에 걸쳐 수행할 수 있도록 지원하는 제품과 서비스를 구축합니다.

BlockSec은 권위 있는 학술 컨퍼런스에 다수의 블록체인 보안 논문을 발표했으며, DeFi 애플리케이션의 여러 제로데이 공격을 보고했고, 2,000만 달러 이상을 구제하는 복수의 해킹을 차단했으며, 수십억 달러 규모의 암호화폐를 보호했습니다.

Sign up for the latest updates
~$160만 손실: Moke 토큰, LpdFi 익스플로잇 | BlockSec 위클리
Security Insights

~$160만 손실: Moke 토큰, LpdFi 익스플로잇 | BlockSec 위클리

2026년 8월 3~9일, BNB 체인에서 2건의 보안 사고가 발생해 총 약 160만 달러의 손실이 발생했으며, 모두 가격 조작이 원인이었습니다. LpdFi(약 69.7만 달러)는 PancakeSwap 유동성 풀을 주문 평가와 이자 정산에 동시 사용해 공격자가 원금을 부풀리고 과도한 이자를 탈취했습니다. Moke Token(약 90.6만 달러)은 조작 가능한 현물 가격과 중복 LP 배당 회계를 결합해 MOKE를 부풀려 BNB 배당을 반복 수령했습니다.

COLDCARD 사건: 지갑의 "무작위" 시드가 무작위가 아니었을 때
Security Insights

COLDCARD 사건: 지갑의 "무작위" 시드가 무작위가 아니었을 때

COLDCARD 펌웨어의 빌드 통합 버그로 비트코인 시드 생성이 취약한 소프트웨어 RNG로 라우팅되어 지갑 시드가 오프라인 복구 가능해졌습니다. 시드 자체의 취약점이므로 펌웨어 업데이트로 해결 불가하며, 2026년 8월 7일 기준 확인된 피해는 1,405 BTC(~9,100만 달러), 비공개 추정치는 최대 2,055 BTC입니다.

~$88M 손실: COLDCARD 및 LULA 익스플로잇 | BlockSec 위클리
Security Insights

~$88M 손실: COLDCARD 및 LULA 익스플로잇 | BlockSec 위클리

2026년 7월 27일~8월 2일, 비트코인과 BNB 체인에서 약 8,800만 달러 손실을 유발한 두 건의 보안 사고가 발생했습니다. COLDCARD 사고는 하드웨어 지갑 펌웨어의 엔트로피 오류로, RNG 매크로 활성화 여부 미확인으로 결정론적 폴백이 실행되어 약 1,370 BTC(~8,800만 달러)가 탈취됐습니다. BNB 체인의 LULA 토큰은 비즈니스 로직 취약점으로 `recycle()` 함수가 악용되어 PancakeSwap V2 유동성에서 약 57만 8천 달러가 유출됐습니다.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit
#4 GMX 사고: 크로스 컨트랙트 재진입 공격으로 4년된 보안 가드 우회