---
title: "가짜 사고 보고서가 찌른 오픈소스 공급망 보안의 진짜 아픈 곳"
published: 2026-05-10T17:43:10.000Z
canonical: https://jeff.news/article/2324
---
# 가짜 사고 보고서가 찌른 오픈소스 공급망 보안의 진짜 아픈 곳

이 글은 실제 보안 사고 보고서처럼 보이지만, 자바스크립트·러스트·파이썬 생태계의 공급망 보안 문제를 과장된 풍자로 풀어낸 글이다. 피싱, 탈취된 패키지 권한, 전이 의존성, 벤더링, 느린 대응, 형식적인 사후분석까지 요즘 개발 생태계의 약한 고리를 한 번에 찌른다.

## 사고는 피싱 하나로 시작해서 생태계 전체를 탔다

- 이 글은 진짜 사고 보고서 형식을 빌린 풍자지만, 찌르는 지점은 꽤 현실적임
  - 상태는 '해결됨, 우연히'이고 심각도는 'Critical → Catastrophic → Somehow Fine'
  - 영향 시스템은 그냥 'Yes'라고 적어놓음. 이 정도면 보안팀의 영혼이 나간 문서 양식임

- 첫 발단은 자바스크립트 패키지 관리자 계정 탈취임
  - left-justify라는 패키지 관리자가 교통카드, 오래된 노트북, 그리고 '쿠버네티스가 토해낸 것처럼 생긴 뭔가 중요한 것'을 도난당함
  - 하드웨어 2단계 인증 키를 잃어버린 뒤, 검색 결과 상단 AI 요약이 안내한 가짜 YubiKey 사이트에 계정을 입력함
  - 공격자는 이 계정으로 패키지에 postinstall 스크립트를 넣고 .npmrc, .pypirc, Cargo 자격 증명, RubyGems 자격 증명을 빼감

- 그다음 공격은 Rust 생태계로 넘어감
  - 탈취된 자격 증명 중에는 vulpine-lz4라는 Rust 압축 라이브러리 관리자의 권한도 있었음
  - 이 라이브러리는 GitHub 별이 12개뿐인데, cargo 자체의 전이 의존성이라는 설정임
  - 버전 0.4.1에는 build.rs가 추가되고, 호스트명이 build, ci, action, jenkins, travis 같은 문자열을 포함하면 셸 스크립트를 내려받아 실행함

> [!WARNING]
> 글은 농담이지만, postinstall 스크립트와 build.rs가 빌드 환경에서 실행된다는 점은 진짜 위험 포인트임. CI는 권한과 비밀값을 많이 들고 있어서 공격자 입장에선 맛집임.

## Python 빌드 도구까지 번지면서 사고가 커진다

- 공격은 snekpack이라는 Python 빌드 도구로 이어짐
  - snekpack은 이름에 data가 들어간 PyPI 패키지의 60%가 쓴다는 설정임
  - 이 도구는 'Rust는 메모리 안전하니까'라는 이유로 vulpine-lz4를 벤더링하고 있었음
  - 결국 snekpack 3.7.0이 악성 코드를 포함한 채 배포되고, 전 세계 개발자 머신에 설치됨

- 악성 동작도 일부러 과장돼 있는데, 실제 사고에서 볼 법한 것들이 섞여 있음
  - ~/.ssh/authorized_keys에 SSH 키를 추가함
  - 화요일에만 켜지는 리버스 셸을 설치함
  - 사용자의 기본 셸을 fish로 바꾸는데, 이건 버그로 추정된다는 농담까지 붙음

- 탐지와 대응은 더 씁쓸한 쪽으로 흘러감
  - 보안 연구자가 이슈를 열었지만 관리자가 복권에 당첨돼 포르투갈에서 염소 농장을 알아보는 중이라 답이 없음
  - 한 주니어 개발자가 벤더링된 라이브러리를 되돌리는 PR을 열지만, 승인자 두 명이 자고 있어서 대기함
  - 사고 대응 Slack은 'compromised' 철자를 미국식으로 쓸지 말지 45개 메시지를 낭비함

## 제일 웃긴 해결책은 악성 웜이었다

- 사고를 끝낸 건 보안 프로세스가 아니라, 전혀 무관한 암호화폐 채굴 웜임
  - cryptobro-9000이라는 웜이 jsonify-extreme 취약점을 타고 퍼짐
  - 이 웜은 공격면을 넓히려고 감염된 머신에서 npm update와 pip install --upgrade를 실행함
  - 그 결과 snekpack이 우연히 3.7.1로 올라가고, 혼란스러운 공동 관리자가 이전 벤더링 버전으로 되돌린 덕에 악성 코드가 제거됨

- 피해 규모도 일부러 말도 안 되게 쓰였지만, 공급망 사고의 감각은 잘 살아 있음
  - 악성 코드는 약 420만 개발자에게 배포됐다고 설정됨
  - 암호화폐 웜이 구한 머신도 약 420만 대라고 추정됨
  - 최종 보안 태세 변화는 '불편함'으로 정리됨. 틀린 말은 아닌 듯함

> [!IMPORTANT]
> 이 글의 핵심 농담은 '공급망 보안이 우연히 좋아졌다'는 부분임. 자동 업데이트, 핀 고정, 벤더링, 2FA가 전부 필요하지만 각각 다른 실패 모드도 만든다는 점을 세게 꼬집음.

## 진짜 메시지는 사후대응 문구가 아니라 책임 구조다

- 근본 원인은 '쿠버네티스라는 이름의 개가 YubiKey를 먹었다'로 끝나지만, 기여 요인은 훨씬 현실적임
  - 주간 다운로드 1천만 미만 패키지에는 여전히 비밀번호만으로 인증이 가능하다는 설정
  - 검색 AI가 존재하면 안 되는 URL을 자신 있게 추천함
  - npm식 작은 패키지 철학이 Rust 생태계로 옮겨가며 핵심 인프라 깊숙이 들어감
  - Python 빌드 도구가 성능 때문에 Rust 라이브러리를 가져와 놓고 업데이트를 안 함

- 개선책 목록은 일부러 서로 충돌하게 적혀 있음
  - 아티팩트 서명은 2022년 3분기 사고의 액션 아이템인데 아직 백로그에 있음
  - 의무 2FA는 이미 있었지만 도움이 안 됨
  - 의존성을 고정하면 보안 패치를 못 받고, 고정하지 않으면 공급망 공격을 받음
  - Rust로 다시 쓰자는 말에는 이미 Rust 라이브러리가 사고 경로였다는 몸짓만 남음

---

## 기술 맥락

- 이 글이 웃긴 이유는 의존성 그래프의 책임자가 없다는 현실을 정확히 찌르기 때문이에요. 앱 개발자는 직접 설치한 패키지만 봤다고 생각하지만, 실제 빌드에는 npm, Cargo, PyPI, 벤더링된 코드, CI 스크립트가 한꺼번에 끼어들거든요.

- postinstall 스크립트나 build.rs가 무서운 이유는 설치와 빌드가 곧 실행이 되기 때문이에요. CI 환경에는 배포 토큰, 레지스트리 권한, SSH 키 같은 민감한 값이 많아서, 패키지 하나가 오염되면 단순 라이브러리 버그가 아니라 계정 탈취로 번질 수 있어요.

- 버전 핀ning도 답이 하나로 떨어지지 않아요. 버전을 고정하면 갑작스러운 악성 업데이트는 피할 수 있지만, 보안 패치도 늦게 들어와요. 반대로 자동 업데이트를 열어두면 패치는 빨리 받지만, 오염된 릴리스도 빨리 받는 구조가 돼요.

- 그래서 현실적인 방어는 한 방짜리 해결책보다 여러 층을 쌓는 쪽이에요. 패키지 서명, 배포 권한 최소화, CI 비밀값 격리, 의존성 감사, 의심스러운 설치 스크립트 차단이 같이 가야 의미가 있어요.

## 핵심 포인트

- 가짜 npm 레지스트리 피싱으로 시작해 npm, Cargo, PyPI로 악성 코드가 번지는 흐름을 풍자
- 주간 8억4700만 다운로드 패키지와 12개 별짜리 러스트 크레이트가 동시에 중요한 인프라가 되는 현실을 꼬집음
- 약 420만 개발자에게 악성 코드가 퍼졌다는 설정으로 공급망 사고의 폭발력을 보여줌
- 보안 조치 목록이 서로 충돌하는 현실적인 딜레마를 농담처럼 정리

## 인사이트

웃기려고 쓴 글인데 웃고 나면 찝찝한 타입이다. 패키지 생태계의 진짜 문제는 특정 언어나 도구 하나가 아니라, 아무도 전체 의존성 그래프를 책임지지 않는 구조에 가깝다.
