# GitLab, 광범위한 NPM 공급망 공격 발견

> Clean Markdown view of GeekNews topic #24689. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24689](https://news.hada.io/topic?id=24689)
- GeekNews Markdown: [https://news.hada.io/topic/24689.md](https://news.hada.io/topic/24689.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-29T01:33:38+09:00
- Updated: 2025-11-29T01:33:38+09:00
- Original source: [about.gitlab.com](https://about.gitlab.com/blog/gitlab-discovers-widespread-npm-supply-chain-attack/)
- Points: 1
- Comments: 1

## Topic Body

- **npm 생태계** 전반에서 **파괴적 악성코드 변종**이 확산 중이며, GitLab 보안팀이 이를 탐지  
- 악성코드는 **Shai-Hulud**의 진화된 형태로, 감염된 개발자의 다른 패키지까지 자동 감염시키는 **웜형 전파 구조**  
- GitHub·AWS·GCP·Azure 등에서 **자격 증명 탈취** 후, 공격자 제어 GitHub 저장소로 **데이터 유출**  
- GitHub 및 npm 접근이 동시에 차단되면 **사용자 데이터를 즉시 삭제하는 ‘데드맨 스위치’** 내장  
- GitLab은 자사 시스템이 감염되지 않았음을 확인했으며, **Dependency Scanning**과 **GitLab Duo Chat**을 통한 탐지·대응 방안 제공  

---

### 공격 개요
- GitLab **Vulnerability Research 팀**이 npm 생태계에서 대규모 공급망 공격을 탐지  
  - 내부 모니터링 시스템이 여러 감염된 패키지를 발견  
  - 악성코드는 **Shai-Hulud**의 변종으로 확인  
- 악성코드는 **웜형 전파**를 통해 감염된 개발자의 다른 패키지까지 자동 감염  
- GitLab은 자사에서 악성 패키지를 사용하지 않았음을 확인하고, 보안 커뮤니티와 정보를 공유  

### 공격 내부 구조
- 내부 모니터링 시스템이 탐지한 악성 npm 패키지는 다음 기능을 수행  
  - GitHub, npm, AWS, GCP, Azure의 **자격 증명 수집**  
  - 탈취한 데이터를 **공격자 제어 GitHub 저장소**로 전송  
  - 피해자의 다른 패키지를 자동 감염  
  - **인프라 접근이 차단되면 파괴적 페이로드 실행**  
- 여러 감염 패키지가 확인되었으며, 조사가 계속 진행 중  

### 기술 분석: 공격 진행 방식

#### 초기 감염 벡터
- 악성코드는 다단계 로딩 과정을 통해 시스템에 침투  
  - 감염된 패키지의 `package.json`에 **`setup_bun.js`** 스크립트가 추가  
  - 겉보기에는 **Bun JavaScript 런타임 설치용**으로 위장  
  - 실제로는 **`bun_environment.js`** (10MB, 난독화된 페이로드)를 실행  
- 작은 로더 파일과 대형 난독화 페이로드로 구성되어 탐지 회피  

#### 자격 증명 수집
- 실행 즉시 다양한 소스에서 **토큰 및 비밀정보**를 수집  
  - **GitHub 토큰**(`ghp_`, `gho_`)  
  - **AWS, GCP, Azure 자격 증명**  
  - **npm 토큰**(`.npmrc` 및 환경 변수)  
  - **Trufflehog** 도구를 이용해 홈 디렉터리 전체를 스캔, API 키·비밀번호·Git 기록 등 탐색  

#### 데이터 유출 네트워크
- 탈취한 GitHub 토큰으로 **“Sha1-Hulud: The Second Coming.”** 설명이 포함된 공개 저장소 생성  
  - 해당 저장소가 **데이터 드롭박스 역할** 수행  
  - GitHub Actions 러너를 설치해 지속성 확보  
- 권한이 부족한 경우, 동일 마커를 가진 다른 저장소를 검색해 **다른 시스템의 토큰 재활용**  
  - 이를 통해 **분산형 토큰 공유 네트워크** 형성  

#### 공급망 전파
- 탈취한 npm 토큰을 이용해 피해자의 모든 패키지를 감염  
  1. 원본 패키지 다운로드  
  2. `setup_bun.js`를 **preinstall 스크립트**로 삽입  
  3. `bun_environment.js` 페이로드 추가  
  4. 버전 번호 증가  
  5. 감염된 패키지를 npm에 재배포  

### 데드맨 스위치
- 악성코드는 GitHub(데이터 유출)과 npm(전파) 접근을 지속적으로 모니터링  
  - 두 채널 모두 차단되면 **즉시 데이터 파괴 실행**  
- **Windows**: 사용자 파일 삭제 및 디스크 섹터 덮어쓰기  
- **Unix 계열**: `shred` 명령으로 파일 덮어쓰기 후 삭제  
- GitHub 저장소 일괄 삭제나 npm 토큰 대량 폐기 시, **감염된 시스템이 동시에 데이터 삭제를 수행할 위험** 존재  

### 침해 지표 (IoC)
- 주요 탐지 지표  
  - 파일: `bun_environment.js` (악성 post-install 스크립트)  
  - 디렉터리: `.truffler-cache/`, `.truffler-cache/extract/`  
  - 프로세스: `del /F /Q /S "%USERPROFILE%*"`, `shred -uvz -n 1`, `cipher /W:%USERPROFILE%`  
  - 명령어: `curl -fsSL https://bun.sh/install | bash`, `powershell -c "irm bun.sh/install.ps1|iex"`  

### GitLab의 탐지 및 대응 지원
- **GitLab Ultimate 사용자**는 내장 보안 기능으로 즉시 노출 여부 확인 가능  
  - **Dependency Scanning** 활성화 시, `package-lock.json` 또는 `yarn.lock` 내 감염 패키지를 자동 탐지  
  - 감염 패키지가 포함된 머지 요청 시 **경고 표시**  
- **GitLab Duo Chat**과 연동해 빠른 질의 기반 탐지 가능  
  - 예: “Shai-Hulud v2 캠페인에 영향받은 종속성이 있는가?”  
  - **Security Analyst Agent**가 프로젝트 취약점 데이터를 조회해 즉답 제공  
- 여러 저장소를 관리하는 팀은 **CI/CD 기반 자동 탐지**와 **에이전트 기반 신속 대응** 병행 권장  

### 향후 전망
- 이번 공격은 **공격 인프라 보호를 위해 피해자 데이터 파괴를 이용하는 새로운 형태의 공급망 공격**으로 평가  
- GitLab은 커뮤니티와 협력해 **안전한 복구 전략**을 개발 중이며, 자동 탐지 시스템으로 변종을 지속 모니터링  
- 조기 정보 공유를 통해 **데드맨 스위치로 인한 2차 피해 방지**를 목표로 함

## Comments



### Comment 46945

- Author: neo
- Created: 2025-11-29T01:33:39+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=46070203) 
- 한 달 전쯤 귀찮은 작업을 해야 해서 NPM 패키지를 찾았음  
  `brew install npm`을 실행하자 **의존성 폭포**가 쏟아졌고, 잠시 멈춰 리스크와 이득을 생각하다가 결국 `brew uninstall npm`으로 되돌림  
  대신 오래된 **Unix 유틸리티 파이프라인**과 awk로 해결했는데, 지금 생각해보면 최고의 결정이었음
  - 교훈은 명확함 — **웹 기술을 로컬 스크립팅에 쓰지 말아야 함**  
    NPM은 브라우저 호환성 문제를 해결하려 만든 도구라, 브라우저가 없는 환경에서 불필요한 복잡성을 초래함
  - 이런 이유로 **컨테이너화나 가상화**가 필요함  
    Node나 Python처럼 의존성이 많은 생태계의 코드를 메인 시스템에서 직접 실행하면 공급망 공격에 노출될 위험이 큼  
    그래서 나는 아예 Python이나 JS 인터프리터를 기본 시스템에 설치하지 않음
  - 나도 예전엔 npm을 **Docker 컨테이너 안에서만** 돌렸는데, 포럼에서 종종 비웃음을 샀음  
    결국 포기했지만 지금은 그게 맞았던 것 같음
  - 나도 비슷한 경험이 있음. artillery가 끌어오려는 의존성 수를 보고 바로 포기했음
  - 아이러니하게도, 개발자들은 늘 “**상식이 최고의 보안**”이라 말하면서도 검증되지 않은 수많은 패키지를 한 줄 명령으로 설치함

- “GitHub이 악성 저장소를 대량 삭제하면 수천 개 시스템이 동시에 사용자 데이터를 파괴할 수 있다”는 말이 있었는데,  
  마치 인질극 같음 — 그래서 **“인질을 쏴라”** 는 농담이 나옴
  - 하지만 인질(사용자)이 스스로 위험에 들어간 셈이라, 결국 자기 선택의 결과임

- 나도 이번 **npm 공격의 피해자**임  
  GitHub CLI가 HOME 디렉토리에 **평문 OAuth 토큰**을 저장한다는 걸 알고 충격받았음  
  공격자가 접근하면 내 계정으로 거의 모든 행동이 가능했음
  - 사실 GitHub CLI는 **keyring이 없을 때만** 토큰을 평문으로 저장함  
    macOS에서는 OS 키체인에 안전하게 저장됨 — [관련 토론](https://github.com/cli/cli/discussions/7109)
  - 맞음, 하지만 브라우저 쿠키 파일도 비슷한 문제를 가짐  
    Chrome은 OS 보호 기능을 쓰지만 Firefox는 아직 아님  
    결국 **sandbox 기반 접근 제어**가 근본적인 해결책임
  - 모든 토큰은 **보호된 키체인**에 있어야 함  
    하지만 플랫폼 간 일관된 솔루션이 없고, MacOS에서도 완벽한 방법이 없음
  - 나도 피해자임. Backstage 설치 후 감염됨  
    `~/.dev-env` 디렉토리가 생기며 내 노트북이 **GitHub runner**로 변했음  
    Bluefin Linux의 **읽기 전용 파일 시스템** 덕분에 피해가 줄었을지도 모름

- 모두 npm만 탓하지만, **GitHub의 책임**도 큼  
  악성 저장소를 빠르게 탐지하지 못했고, 이미 **악성코드 저장소 문제**가 심각함
  - 그래도 GitHub에 업로드된 덕분에 피해를 빨리 알아챈 사람도 있었음  
    만약 몰래 외부 서버로 전송됐다면 더 끔찍했을 것임
  - Microsoft가 모든 걸 필터링해줄 순 없음  
    **커뮤니티 차원의 도구와 관행**이 필요함
  - GitHub이 Microsoft 소유라 **GoLang 패키지 저장소**와도 얽혀 있음  
    상업적 규제나 빌드 워크플로 제한이 생기면 큰 문제로 이어질 수 있음
  - 두 회사 모두 **보안 수준이 평범**하다는 점은 부정할 수 없음
  - 이 악성코드는 동일한 패턴으로 저장소를 생성하므로, 간단한 규칙으로도 탐지 가능했을 것임

- 왜 **NPM만 공격 대상**이 되는지 궁금했음  
  Python이나 Java도 인기 많은데, 최근엔 조용함  
  - NPM은 **post-install hook**으로 임의 명령 실행이 가능하고,  
    **버전 범위 의존성** 문화 덕분에 감염이 빠르게 확산됨  
    Java는 특정 버전 고정이 일반적이라 이런 일이 드묾
  - Node는 **표준 라이브러리가 작고 커뮤니티 의존도가 높음**  
    그래서 하나의 패키지가 수십 개의 하위 의존성을 끌어옴
  - JS는 GitHub에서 가장 인기 있는 언어라 **공격 표면이 넓고**  
    경험이 적은 개발자들이 많아 보안이 약함
  - JS 커뮤니티는 “**최신 버전 강박증**”이 심함  
    다른 언어 생태계는 검증 후 업데이트하지만 JS는 즉시 업그레이드함
  - NPM은 **보안 경계가 약함**  
    설치 시 스크립트를 자유롭게 실행할 수 있었고, JVM이나 Python은 그렇지 않음

- `.npmrc`에  
  ```
  ignore-scripts=true
  ```  
  를 추가하면 공격 벡터를 줄일 수 있음  
  [관련 글](https://blog.uxtly.com/getting-rid-of-npm-scripts)
  - 설치 전에 **preinstall/postinstall hook**이 있는 패키지를 미리 확인할 방법이 있는지 궁금함
  - “ignore scripts”가 안전하다면 왜 존재하는 옵션인지,  
    비활성화 시 **의존성 깨짐** 위험은 없는지도 의문임
  - 하지만 결국 Node 환경에서 JS를 실행하면 **환경 변수나 파일 접근**은 막을 수 없음
  - 혹은 그냥 **pnpm**을 쓰는 것도 방법임

- 이번 공격에서 가장 걱정되는 건 **자격 증명 탈취**임  
  감염된 패키지를 설치했다면 환경 변수나 `.npmrc` 토큰이 유출됐을 수 있음  
  즉시 **토큰과 API 키를 회전**해야 함  
  주기적 회전은 침해 후 대응이 아니라 **사전 예방책**임
  - 개발자가 **비밀번호 재사용**을 한다면 정말 심각한 문제임  
    자격 증명은 환경 변수나 파일에 저장하지 말고 **보안 키나 암호화 파일**을 써야 함
  - 감염 여부를 모른다면 먼저 **감염 탐지 → 정리 → 토큰 회전** 순으로 해야 함
  - 이번 공격은 단순한 감염이 아니라 **생태계 전체를 인질로 잡는 형태**라 더 위험함  
    마치 **분산 원장에 악성 트랜잭션**을 심는 것 같음
  - 비밀은 반드시 **보안 저장소(secret locker)** 에 보관해야 함  
    여전히 많은 서비스가 평문 저장을 기본값으로 두는 게 문제임
  - 그리고 이 악성코드는 **전파가 멈추면 데이터 파괴**까지 시도함

- 이런 공격이 반복되는데, 왜 **AI 기반 탐지 시스템**이 작동하지 않는지 의문임  
  Microsoft가 AI를 그렇게 강조하는데, 정작 GitHub 보안엔 안 쓰이는 듯함
  - 하지만 “AI가 공격을 탐지했다”는 말은 이미 **보안 마케팅의 상투어**가 됨  
    방화벽이 막은 모든 시도를 공격으로 분류하던 시절처럼 의미가 퇴색됨
  - 우리 회사는 **SonaType Lifecycle**을 쓰는데, AI 기반으로 이런 공격을 막는다고 함  
    내부적으로 **SonaType IQ Server**가 이를 지원함
  - 현재의 “AI”는 **생성형 모델**이라 평가보다는 생성에 초점이 맞춰져 있음  
    실제로 curl 프로젝트가 **AI 생성 보안 리포트 스팸**에 시달린 사례도 있음

- **postinstall 스크립트**를 계속 허용할 이유가 있는지 궁금함  
  사용자에게 실행 여부를 묻는 게 낫지 않을까 생각함
  - 하지만 대부분의 사용자는 “예”를 누를 것이고,  
    CI 서버에서는 **비대화식 설치**가 필요하므로 현실적으로 어렵다고 봄

- 글이 매우 통찰력 있었는데, 마지막에 **GitLab 보안 기능 홍보**로 끝나서 아쉬웠음
  - GitLab 사용자라면 유용했을 수도 있음
  - 그래도 그게 글의 **통찰력 자체를 깎지는 않음**
