---
title: "npm의 기본 설정이 나쁜 이유 — axios 공격으로 다시 드러난 JavaScript 공급망의 구조적 문제"
published: 2026-03-31T17:49:43.000Z
canonical: https://jeff.news/article/1441
---
# npm의 기본 설정이 나쁜 이유 — axios 공격으로 다시 드러난 JavaScript 공급망의 구조적 문제

axios npm 패키지 탈취 사건을 계기로 npm 클라이언트의 기본 설정이 공급망 공격을 구조적으로 허용하는 이유를 분석. 락파일 자동 수정, postinstall 기본 실행, npx 무방비, trusted publishing 해제 가능 등 핵심 문제점과 pnpm/Bun/Deno의 대안을 비교.

- axios npm 패키지가 또 공격당함 — 공격자가 관리자 계정을 탈취, RAT(원격 접근 트로이목마)를 담은 악성 버전을 2~3시간 동안 배포
  - axios는 주간 다운로드 8,300만 건. 이런 공급망 공격이 JavaScript에서만 유독 반복되는 이유가 npm 클라이언트의 기본 설정(defaults) 때문이라는 분석

## npm install이 락파일을 덮어씀

- `npm install`은 `package.json`과 `package-lock.json` 사이에 드리프트가 감지되면 **락파일을 조용히 수정함**
  - 실제로 원하는 동작은 `npm ci` — 락파일 불일치 시 설치 거부, 수정 안 함
  - 대부분의 개발자가 `npm ci`를 CI에서 뭔가 깨진 후에야 발견하고, 많은 경우 아예 모름

## 라이프사이클 스크립트가 기본으로 실행됨

- `npm install` 시 모든 의존성과 전이 의존성이 `postinstall` 스크립트를 통해 **임의 코드를 실행할 수 있음**
  - 실제로 필요한 건 C/C++ 바인딩 컴파일하는 네이티브 애드온 정도인데, npm은 모든 패키지에 이 권한을 기본으로 부여
  - axios 공격이 정확히 이 메커니즘을 사용 — `plain-crypto-js`의 깨끗한 버전을 18시간 먼저 게시 → 페이로드 담은 두 번째 버전 → axios 의존성으로 추가 → 설치 시 자동 RAT 설치

> [!WARNING]
> pnpm v10은 postinstall 스크립트를 기본 차단하고 allow-list 방식으로 전환함. Bun도 `trustedDependencies`로 opt-in 방식. npm은 v11.10.0에서 `npm trust`를 추가했지만 **기본값은 그대로** — 설정하지 않으면 모든 패키지가 스크립트 실행 가능.

## Trusted Publishing의 허점

- npm의 OIDC 기반 trusted publishing은 CI에서 장기 토큰 없이 배포할 수 있게 해줌 — 좋은 기능
  - 하지만 관리자(또는 계정 탈취한 공격자)가 **언제든 trusted publishing을 끄고 토큰 기반으로 되돌릴 수 있음**
  - 소비자에게는 이 변경에 대한 시그널이 전혀 없음
  - trusted publishing 활성화는 npm 지원팀만 해제 가능한 **단방향 전환**이어야 함

## npx는 안전장치가 아예 없음

- npx는 락파일을 사용하지 않음 — 최신 버전을 그대로 가져와서 즉시 실행
  - 쿨다운도 없고 핀 버전도 없음
  - 공격자가 인기 npx 타겟의 악성 버전을 올리면 그 순간부터 모든 호출이 공격 코드를 받음
  - 튜토리얼, CI 스크립트, **AI 코딩 에이전트가 npx 명령을 생성해서 실행**하는 워크플로우에서 특히 위험

## 쿨다운과 GitHub Actions 문제

- `min-release-age`(v11.10.0)로 최근 게시된 버전 설치를 거부할 수 있지만, 기본값이 꺼져 있어서 모르면 못 씀
  - 대부분의 악성 버전이 24~48시간 내 잡히므로 적당한 쿨다운만 있어도 대부분의 공급망 공격을 차단 가능
- npm이 클래식 토큰을 폐기하고 90일 수명 제한을 걸었지만, GitHub Actions에서 토큰이 repository secrets에 저장되는 구조는 변함없음
  - Shai-Hulud 공격이 바로 CI 환경에서 토큰을 수확하는 방식이었고, Trivy 공급망 침해도 같은 공격면 — 유출 토큰으로 76개 버전 태그에 악성 코드 강제 푸시

## npm이 바꿔야 할 것

- pnpm, Bun, Deno 모두 더 나은 기본값을 선택했지만, **npm이 Node.js와 함께 배포되는 기본 클라이언트**라 다른 도구의 개선이 생태계 전체 보안 수준을 바꾸지 못함
  - npm은 더 안전한 옵션을 플래그나 설정 키로 제공하긴 함
  - 하지만 `npm install`이나 `npx`를 플래그 없이 칠 때 **기본으로** 일어나는 일을 바꾸지 않으면 의미가 없음
  - OpenSSF의 "secure by default" 원칙이 정확히 이걸 말하는 것

---

## 기술 맥락

- `npm install`과 `npm ci`의 차이가 왜 중요하냐면, 개발 중에 `npm install`을 쓰면 락파일이 변경되면서 의존성 트리가 미묘하게 달라질 수 있어요. CI에서 `npm ci`를 쓰는 건 상식이 되었지만, 로컬 개발에서도 의도치 않은 의존성 변경을 인지하는 게 중요함
- postinstall 스크립트 차단이 pnpm/Bun에서는 기본인데 npm에서는 여전히 opt-in인 이유는 하위 호환성 때문이에요. 네이티브 모듈(node-gyp 등)이 postinstall에 의존하는 패키지가 아직도 상당수 있어서 기본 차단하면 기존 프로젝트가 대량으로 깨지거든요. 하지만 보안 관점에서는 이미 한참 넘은 문제
- npx가 AI 에이전트 워크플로우에서 위험하다는 지적은 꽤 시의적절해요. Claude Code, Copilot 같은 에이전트가 `npx create-xxx`를 자동으로 실행하는데, 에이전트는 패키지 진위를 검증하지 않으니까 악성 패키지가 끼어들 여지가 커요

## 핵심 포인트

- npm install이 락파일을 조용히 수정하는 게 기본 동작
- postinstall 스크립트가 모든 의존성에 기본 허용 — axios 공격이 이걸 사용
- npx는 락파일/쿨다운/핀 없이 최신 버전을 바로 실행
- trusted publishing을 관리자가 언제든 해제 가능
- pnpm/Bun은 이미 더 안전한 기본값을 채택했지만 npm이 기본 클라이언트

## 인사이트

npm의 문제는 안전한 옵션이 없는 게 아니라 기본값이 안전하지 않다는 것. 스캐너나 정책보다 기본 설정 하나 바꾸는 게 공급망 보안에 더 큰 영향을 줌.
