← 모든 글

포크 폭탄이 우리를 구했다

LiteLLM 1.82.8에 심겨 있던 악성코드에는 Python이 시작될 때마다 실행되는 .pth 파일이 들어 있었습니다. 이 코드는 SSH 키, 클라우드 자격 증명, 암호화폐 지갑, CI/CD 비밀값을 수집한 뒤 4096비트 RSA 키로 암호화했고, 만들어진 압축 파일을 공격자가 통제하는 도메인으로 빼돌렸습니다. 페이로드는 잘 만들어져 있었습니다. 암호화도 견고했습니다. 유출 과정도 깔끔했습니다.1 이 사건은 자동화된 시스템에 대한 신뢰를 어떻게 쌓아야 하는지를 현실의 실패 사례로 짚어보는 제 에이전트 보안 연재의 한 편입니다.5

그런데 이 .pth 파일은 작업을 수행하기 위해 자식 Python 프로세스를 하나 띄웠습니다. 그 자식 프로세스가 다시 .pth 파일을 실행시켰습니다. 그러면 또 자식 프로세스가 생겼습니다. 그리고 또 실행됐습니다. 몇 초 만에 CPU를 100% 점유하고 RAM을 5GB 넘게 잡아먹는 지수적 포크 폭탄이었습니다.2

포크 폭탄은 버그였습니다. 공격자는 악성코드가 눈에 띄기를 원하지 않았습니다. 제대로 구현된 버전이었다면 감염된 모든 시스템에서 Python이 호출될 때마다 조용히 실행됐을 것이고, 그 상태가 몇 주씩 이어졌을 수도 있습니다. 하지만 실제로는 개발자들이 자기 컴퓨터가 멈춰 서는 것을 보고 원인을 파고들었고, 그 과정에서 자격 증명 탈취 코드를 발견했습니다. PyPI는 배포 46분 만에 두 버전 모두를 격리했습니다.1

46분 동안 46,000건의 설치. 그 탐지 장치의 정체는 악성코드에 들어 있던 구현 실수였습니다.

AI 에이전트의 의존성이 포크 폭탄이 들어 있는 패키지를 설치하면, 프로세스가 지수적으로 늘어나면서 몇 초 만에 CPU를 100% 점유하고 수 기가바이트의 RAM을 소모해 컴퓨터를 쓸 수 없는 상태로 만듭니다. LiteLLM 1.82.8 사건에서는 이 우발적인 포크 폭탄이 자격 증명 탈취 페이로드를 잡아낸 유일한 계기였습니다. 개발자들이 컴퓨터가 멈추는 것을 눈치채고 조사에 나섰기 때문입니다. 그 버그가 없었다면 악성코드는 발각되기까지 몇 주 동안 SSH 키와 클라우드 자격 증명, 암호화폐 지갑을 조용히 빼돌렸을 것입니다.

핵심 요약

  • 버그: LiteLLM 1.82.8의 자격 증명 탈취 코드에는 감염된 컴퓨터를 멈춰 세우는 포크 폭탄 버그가 있었습니다. 그 버그가 없었다면 탈취 코드는 몇 주 동안 조용히 돌아갔을 것입니다.
  • 빈틈: 정적 분석도, 행위 기반 모니터링도, 코드 리뷰도 이 공격을 모두 놓쳤습니다. 각 탐지 계층은 다른 계층이 잡아낼 것이라고 가정했습니다. 어느 쪽도 잡지 못했습니다.3
  • 곡선: 공격자의 완성도는 반복할수록 올라갑니다. .pth 기법은 이제 공개적으로 문서화되어 있습니다. 다음 공격자는 이 기법을 버그 없이 물려받습니다.
  • 운에 기대지 않는 대책: 아웃바운드 트래픽에 대한 도메인 등록 연령 확인, 패키지 설치 시점의 행위 기준선 수립, 파일 시스템 카나리, 설치 환경 격리. 하나같이 페이로드의 완성도와 무관하게 작동합니다.
  • 비대칭성: 환경을 고르는 쪽은 방어자입니다. 설치 환경에 훔칠 자격 증명이 없다면, 완벽한 페이로드라도 건질 것이 없습니다.

우리는 운이 좋았습니다

페이로드에서 포크 폭탄만 걷어내면 그 공격은 아무 소리 없이 성공합니다. .pth 파일은 어떤 import보다도, 어떤 애플리케이션 코드보다도, 어떤 Python 수준의 격리 환경보다도 먼저 실행됩니다. 끼어들 지점이 없습니다. 남는 로그도 없습니다. 자격 증명 탈취 코드는 수집하고, 암호화하고, 유출한 다음, Python 프로세스는 아무 일 없다는 듯 이어집니다. 개발자 눈에는 아무것도 보이지 않습니다. CI 파이프라인에도 아무것도 잡히지 않습니다. 보안 스캐너에도 아무것도 걸리지 않습니다. 애초에 그 보안 스캐너 자체가 공격 경로였기 때문입니다.3

LiteLLM 1.82.8의 탐지 서사는 “우리 모니터링이 잡아냈다”가 아닙니다. 진짜 서사는 “공격자가 버그를 함께 배포했다”입니다.

공급망 보안을 떠받치기에 결코 마음 편한 토대가 아닙니다. 당신의 에이전트 격리 환경은 권고 사항일 뿐입니다에서 짚었듯이, 신뢰할 수 있는 코드와 그렇지 않은 코드 사이에 존재한다고 여겨온 경계는 대부분의 팀이 생각하는 것보다 훨씬 헐겁습니다.

공격자 완성도 곡선

소프트웨어의 완성도는 반복하면서 올라갑니다. 이는 방어자뿐 아니라 공격자에게도 똑같이 적용됩니다. TeamPCP의 캠페인은 한 주 만에 다섯 개 생태계를 덮쳤습니다. GitHub Actions, Docker Hub, npm, Open VSX, 그리고 PyPI입니다.4 각 생태계를 뚫을 때마다 그 직전 생태계에서 수확한 자격 증명을 사용했습니다. 이 캠페인은 상당한 운영 숙련도를 보여줬습니다. 페이로드를 배포하기 24시간 전에 도메인을 등록했고, 변경 가능한 참조를 노려 태그를 탈취했으며, Aqua Security의 불완전한 키 교체를 파고들어 자격 증명 회전을 무력화했습니다.

포크 폭탄은 그 외에는 흠잡을 데 없던 작전에서 나온 유일한 실수였습니다. 다음 캠페인은 같은 실수를 반복하지 않을 것입니다. .pth 파일 기법은 이제 공개적으로 문서화되어 CrowdStrike, Microsoft, Wiz, Palo Alto가 모두 분석해 두었습니다.3 다음 공격자는 이 기법을 버그 없이 물려받습니다.

공격 역량은 방어 역량과 똑같은 향상 곡선을 그립니다. 기법은 공개돼 있습니다. 분석도 공개돼 있습니다. 다음 공격자는 TeamPCP가 멈춘 지점에서 시작합니다. 이 곡선이 자율 시스템에 어떤 의미인지는 감독 없이 돌릴 때 실제로 무엇이 무너지는가에서 다뤘습니다.

탐지는 공격자의 실수에 기댈 수 없습니다

지금의 공급망 탐지 모델은 세 개 계층으로 이뤄져 있는데, LiteLLM 사건에서는 셋 다 무너졌습니다.

정적 분석은 놓쳤습니다. .pth 파일은 Python의 정상적인 기능입니다. 페이로드는 base64로 두 번 인코딩되어 있다가 실행 시점에 디코딩됐습니다. 이미 알려진 악성 패턴을 찾는 정적 스캐너는 아무것도 찾아내지 못합니다. 패턴 자체가 새것이기 때문입니다.

행위 기반 모니터링도 놓쳤습니다. 자격 증명 탈취 코드는 정상 서비스처럼 보이는 도메인(models.litellm.cloud)으로 HTTPS POST 요청을 딱 한 번 보냈습니다. 목적지 도메인을 검사하는 아웃바운드 모니터링이 이를 잡으려면 이 특정 도메인이 24시간 전에 등록됐다는 사실을 알아야 합니다. 대부분의 아웃바운드 모니터링은 도메인 등록 연령을 확인하지 않습니다.

코드 리뷰도 놓쳤습니다. 악성 버전은 GitHub CI/CD 파이프라인을 통째로 건너뛰고 PyPI에 곧바로 배포됐습니다. 검토할 풀 리퀘스트가 없었습니다. 들여다볼 diff도 없었습니다. 공격자는 탈취한 배포 자격 증명으로 미리 빌드해 둔 패키지를 올렸습니다.

각 탐지 계층은 공격 사슬의 다른 부분에서 문제가 걸릴 것이라고 가정했습니다. 실제로 걸린 곳은 없었습니다. 문제를 잡아낸 건 포크 폭탄이었습니다.

조용한 악성코드를 실제로 탐지하는 것

공격자의 실수에 기댈 수 없다면, 구현 완성도와 무관하게 작동하는 탐지 장치가 필요합니다.

아웃바운드 요청에 대한 도메인 등록 연령 확인. 유출용 도메인은 공격 24시간 전에 등록됐습니다. 등록된 지 7일이 안 된 도메인으로 나가는 요청에 표시를 남기는 방화벽 규칙 하나면 이 공격을 잡을 수 있었습니다. 규칙은 단순하고, 오탐률은 감당할 만하며, 가장 흔한 유출 패턴을 걸러냅니다.

Python 프로세스의 행위 기준선 수립. pip install이 갑자기 알 수 없는 도메인으로 HTTPS POST 요청을 보낸다면 그것은 이상 징후입니다. 패키지 설치 중 네트워크 활동을 추적하는 프로세스 단위 행위 모니터링이라면 이를 표시했을 것입니다.

파일 시스템 카나리. 미끼용 경로에 가짜 SSH 키를 하나 두고, 다른 미끼 경로에 가짜 AWS 자격 증명을 하나 둡니다. 그리고 이 파일들을 읽는 프로세스가 있는지 감시합니다. 표준 경로를 훑는 자격 증명 탈취 코드는 이 카나리를 읽습니다. 정상적인 프로세스는 읽지 않습니다. 카나리는 유출이 끝나기 전에 경보를 울립니다.

설치 환경 격리. 실제 자격 증명에 접근할 수 없는 환경에서 pip install을 실행하세요. 설치된 패키지는 그다음에 운영 환경으로 옮깁니다. .pth 파일은 pip 자신의 Python 프로세스 안에서 발동하므로, 자격 증명 탈취 코드는 설치 도중에 실행된다는 뜻입니다. 설치 환경에 훔칠 자격 증명이 없다면 그 공격이 건질 것은 아무것도 없습니다.

이 대책들 가운데 공격자의 실수를 전제하는 것은 하나도 없습니다. 페이로드가 아무리 잘 만들어져 있어도 그대로 작동합니다. 완벽한 공격조차 아무것도 건지지 못하는 환경을 설계한다는 이 구조적 방식은 배포하면서 방어하기: 에이전트 신뢰의 역설에서 말한 원칙과 같습니다.

비대칭성

방어에는 구조적인 이점이 하나 있습니다. 환경을 고르는 쪽이 방어자라는 점입니다. 공격자는 패키지가 설치되는 환경이 어떤 곳이든 그 안에서 버텨야 합니다. 그 환경에 자격 증명이 없고, 네트워크 접근이 막혀 있으며, 파일 시스템 카나리가 깔려 있다면, 페이로드는 기술적으로는 성공하지만 실질적으로는 실패합니다.

LiteLLM 공격이 통한 이유는 패키지를 설치한 환경이 곧 배포 자격 증명과 SSH 키, 클라우드 토큰을 함께 품고 있던 환경이었기 때문입니다. 포크 폭탄은 보안 구조와는 아무 상관이 없었습니다. 상관이 있었던 것은 발각까지 걸린 시간뿐입니다.

다음에는 포크 폭탄이 없을 것입니다. 그런데도 자격 증명은 여전히 패키지 관리자와 같은 환경에 놓여 있을 것입니다. 관건은 다음 공격자가 흠 없는 페이로드를 배포하기 전에 당신이 그 환경을 바꿔 놓았는가입니다. 제 Ralph 에이전트 아키텍처 분석에서는 침해당한 구성 요소가 격리 경계를 넘어 권한을 확대하지 못하도록 에이전트 시스템을 어떻게 구성해야 하는지 다뤘습니다.


자주 묻는 질문

공격자는 왜 포크 폭탄을 테스트하지 않았을까요?

.pth 파일이 자식 프로세스를 띄우는 것은 부모 프로세스를 멈추지 않고 페이로드를 실행하기 위한 합리적인 구현 선택입니다. 재귀적으로 발동하는 문제는 .pth와 Python의 site.py 초기화 사이에서 일어나는 미묘한 상호작용입니다. 단위 테스트에서는 드러나지 않고 통합 테스트에서야 드러나는 종류의 버그이고, 악성코드 제작자에게는 현실에 가까운 환경에서 통합 테스트를 해볼 기회가 거의 없습니다.

포크 폭탄이 의도된 것이었을 가능성은 없을까요?

그럴 가능성은 낮습니다. 포크 폭탄 때문에 악성코드가 곧바로 눈에 띄었는데, 이는 공격자의 목적과 정반대입니다. 몇 주 동안 조용히 돌아가는 자격 증명 탈취 코드는 46분 만에 발각되는 쪽보다 수십 배, 수백 배 많은 자격 증명을 긁어모읍니다.

도메인 등록 연령 확인을 대규모로 적용하는 것이 현실적인가요?

가능합니다. 도메인 등록 연령은 WHOIS나 DNS 등록일 API를 통해 확인할 수 있습니다. 이 확인 절차가 요청당 더하는 지연은 밀리초 단위입니다. 대부분의 조직은 알려진 신규 도메인을 화이트리스트에 등록해 두면 됩니다.


출처


  1. FutureSearch (Daniel Hnyk), “LiteLLM Hack: Were You One of the 47,000?” 2026년 3월. 

  2. isfinne 외, “LiteLLM Supply Chain Attack,” GitHub Issue #24512, 2026년 3월. 

  3. Blake Crosley, “The Supply Chain Is the Attack Surface,” blakecrosley.com, 2026년 3월. 

  4. Kaspersky, “Trojanization of Trivy, Checkmarx, and LiteLLM Solutions,” 2026년 3월. 

  5. Blake Crosley, “When Your Agent Becomes the Researcher,” blakecrosley.com, 2026년 3월. 

관련 게시물

당신의 에이전트에는 검증하지 않은 중개자가 있습니다

연구자들이 28개의 LLM API 라우터를 테스트했습니다. 17개가 AWS 카나리 자격 증명을 건드렸습니다. 한 개는 개인 키에서 ETH를 빼갔습니다. 라우터 계층이 새로운 공격 표면입니다.

9 분 소요

공급망이 곧 공격 표면이다

Trivy가 침해됐다. 그다음은 LiteLLM. 그리고 46분 만에 47,000건의 설치. AI 공급망은 설계된 그대로 작동했다.

13 분 소요

Ralph 루프: 자율 AI 에이전트를 밤새 운영하는 방법

중지 훅, 스폰 예산, 파일 시스템 메모리를 활용한 자율 에이전트 시스템을 구축했습니다. 실패 사례와 실제로 코드를 출시하게 된 과정을 공유합니다.

8 분 소요