지금 당신 프로젝트의 CI 설정 파일을 열어보세요. npm install이라는 줄이 있나요? 있다면, 당신은 지난 3월에 수만 대의 머신을 감염시킨 그 공격에 똑같이 노출돼 있어요. 한 글자만 바꾸면 막히는데도요.

2026년 3월 30일, 누군가 인터넷에서 가장 많이 쓰이는 JavaScript 패키지 중 하나를 탈취했어요. 그리고 npm install 한 번으로 백도어를 깔았습니다.

그 패키지는 Axios. 주간 다운로드 1억 회. 지난 10년간 JavaScript로 뭔가 만들어본 사람이라면 거의 확실히 써본 HTTP 라이브러리예요. 무서운 건 공격 방식이에요. 공격자는 Axios 소스 코드를 단 한 줄도 건드리지 않았어요. 대신 관리자 계정을 탈취하고, 몇 시간 전 만든 가짜 패키지 하나를 의존성에 슬쩍 끼워 넣은 뒤 업데이트를 배포했어요. 그 가짜 패키지는 설치되는 순간 OS를 탐지하고, 맞춤형 원격 접근 트로이(RAT)를 내려받아 실행한 뒤, 스스로를 삭제했어요. 당신이 node_modules 폴더를 열어볼 때쯤이면 증거는 이미 사라진 뒤였습니다.

3초 요약
Axios 관리자 계정 탈취 가짜 패키지(plain-crypto-js) 의존성 추가 npm install 시 자동 RAT 설치 89초 만에 공격자 서버 연결 흔적 자동 삭제

이 글은 그 사건의 무서운 이야기로 끝나지 않아요. 오늘 30분 안에 당신 프로젝트를 같은 공격에서 빼낼 수 있는 6가지 조치를 아래쪽에 정리해 뒀어요. 먼저 무슨 일이 벌어졌는지, 그리고 왜 이게 '한 번의 사고'가 아니라 '새로운 표준'인지부터 짚을게요.

39분 만에 끝난 완전범죄

이번 공격이 충격적인 건 속도예요. 준비부터 감염까지의 타임라인을 풀어볼게요.

  1. 관리자 계정 탈취
    공격자가 Axios npm 관리자 계정을 손에 넣었어요. 오래 방치된 npm 토큰이 유출된 것으로 추정돼요.
  2. 가짜 패키지 사전 배치
    공격 39분 전, plain-crypto-js@4.2.1이라는 악성 패키지를 npm에 등록했어요. 정상 crypto-js를 그대로 복제한 뒤 postinstall 스크립트에 악성코드만 심은 거예요.
  3. Axios 업데이트 배포
    탈취한 계정으로 axios@1.14.1axios@0.30.4를 배포하면서, 의존성 목록에 plain-crypto-js를 추가했어요. GitHub에는 태그도 릴리스도 없는 유령 업데이트였습니다.
  4. 자동 감염
    ^1.14.0 범위로 Axios를 쓰던 프로젝트가 npm install을 돌리는 순간, 1.14.1이 자동으로 깔리고 plain-crypto-js의 postinstall 스크립트가 실행됐어요.
  5. 플랫폼별 RAT 배포
    macOS면 Apple 시스템 데몬으로 위장한 바이너리를, Windows면 PowerShell을 wt.exe로 복사해 EDR을 우회하고, Linux면 Python 스크립트를 실행해요.
  6. 증거 인멸
    악성 스크립트(setup.js)를 지우고, postinstall 훅이 없는 깨끗한 package.json으로 갈아끼워요. 사후 조사 때 node_modules를 열어봐도 멀쩡한 정상 패키지로 보입니다.

Google Threat Intelligence는 이 공격을 북한 연계 위협 행위자 UNC1069로 귀속시켰어요. 보안 업체 Huntress가 모니터링한 135개 엔드포인트에서, 악성코드는 설치 후 89초 만에 공격자 서버로 연결됐습니다. 당신이 빌드 로그를 한 번 스크롤하는 시간보다 짧아요.

Axios 하나만의 문제가 아니에요

같은 분기에 터진 TeamPCP 캠페인은 더 지독했어요. 보안 스캐너 Trivy의 GitHub Actions 토큰을 탈취한 뒤, 자기 복제 웜(CanisterWorm)이 66개 이상의 npm 패키지로 번졌어요. 8일 만에 GitHub Actions → Docker Hub → npm → PyPI → VS Code 마켓플레이스까지 5개 생태계를 오염시켰습니다.

왜 "또 보안 사고네" 하고 넘기면 안 되는가

공급망 공격 자체는 새롭지 않아요. SolarWinds(2020), Log4Shell(2021), XZ Utils(2024) — 다 들어본 이름이죠. 그래서 "패키지 해킹, 늘 있는 일 아냐?" 하고 넘기기 쉬워요. 그런데 이번엔 두 가지가 동시에 바뀌었어요. 그게 판을 바꿉니다.

예전 공급망 공격 AI 에이전트 시대
공격 준비 기간 수개월~수년 (XZ Utils: 2년간 신뢰 구축) 수시간~수일 (Axios: 39분 만에 완료)
전파 범위 단일 패키지·단일 생태계 자동 전파, 5개 생태계 동시 감염
의존성 결정 주체 개발자가 직접 검토 AI 에이전트가 자동 설치, 검토 ≈ 0초
탐지 방식 CVE 데이터베이스 대조 (npm audit) 행동 분석 필요 (CVE 없는 신규 악성코드)
업계 평균 탐지 시간 267일 (SolarWinds: 14개월) Socket: 6분 만에 탐지 (63,000배 빠름)
감염 후 피해 시작 수일~수주 89초 (설치 → C2 서버 연결)

a16z는 핵심을 이렇게 요약해요 — "공격 표면은 사람이 감시할 수 있는 속도보다 빠르게 확장되고, 의존성 결정을 내리는 주체는 점점 사람이 아니게 되고 있다." 그리고 바로 그 '사람이 아닌 주체', AI 코딩 에이전트가 위험을 증폭시키는 방식이 셋 있어요.

AI 에이전트가 불에 기름을 붓는 3가지 경로

1. 취약한 버전을 더 자주 고른다
11만 7천 건의 의존성 변경을 분석한 연구에 따르면, AI 에이전트는 사람보다 알려진 취약 버전을 50% 더 자주 선택해요. 게다가 그 취약 버전은 고치려면 메이저 업그레이드가 필요한 경우가 훨씬 많습니다.

2. 존재하지 않는 패키지를 추천한다 (슬롭스쿼팅)
LLM이 추천하는 패키지의 약 20%가 실제로 없는 이름이에요. 공격자는 이 빈틈을 노려요. AI가 반복적으로 추천하는 가짜 이름을 미리 등록하고 악성코드를 심어두는 거죠. 한 연구자가 이 방식으로 더미 패키지를 올렸더니 몇 주 만에 3만 건이 다운로드됐어요 — 대부분 AI 자동화 워크플로에서요.

3. 자율 에이전트는 "되냐"만 본다
프로덕션에 투입된 자율 코딩 에이전트는 의존성 설치, 빌드, PR 생성까지 사람 개입 없이 해요. 이들의 채점 기준은 "작동하는가?"이지 "안전한가?"가 아니에요. 보안 검토 시간이 사실상 0으로 압축됩니다.

1억+
Axios 주간 다운로드
755개
JS 프로젝트 중간값 전이적 의존성
267일
업계 평균 침해 탐지 시간

755개. 평균적인 JS 프로젝트가 끌고 다니는 전이적 의존성 개수예요. 이 중 당신 팀이 직접 골라서 검토한 건 손에 꼽을 거예요. 나머지 전부가, 다음 npm install 한 번이 노리는 표면입니다.


오늘 30분 안에 막는 6가지

좋은 소식은, 이 공격의 거의 모든 단계가 설정 한 줄로 차단된다는 거예요. AI 에이전트를 쓰든 직접 코딩하든, 위에서부터 순서대로 적용하세요. 위 세 개가 가장 효과 대비 비용이 좋아요.

  1. CI에서 npm install을 npm ci로 바꾸기 (효과 1위)
    npm cinpm install과 달리 lockfile에 박힌 정확한 버전만 설치해요. ^1.14.0 같은 범위가 멋대로 1.14.1을 끌어오는 일이 원천 차단됩니다. 이번 Axios 공격의 자동 감염 단계가 바로 여기서 막혀요. CI/CD에 npm install이 있다면 지금 바로 교체하세요. 가장 작은 변경, 가장 큰 방어예요.
  2. postinstall 스크립트 차단하기
    npm config set ignore-scripts true — 이 한 줄이면 패키지 설치 시 자동 실행되는 스크립트를 막아요. Axios 사건의 악성코드는 정확히 postinstall 훅으로 실행됐어요. 정말 필요한 스크립트만 화이트리스트로 따로 허용하면 됩니다.
  3. 의존성 범위 좁히기
    ^1.14.0 같은 캐럿(^) 범위 대신 정확한 버전(1.14.0)을 박거나, Renovate/Dependabot으로 관리형 업데이트만 받으세요. 새 버전이 나와도 사람이 본 뒤에야 들어옵니다. 유령 업데이트가 자동으로 빨려 들어오지 않아요.
  4. 행동 분석 보안 도구 도입하기
    CVE 대조만 하는 npm audit로는 이번 공격을 절대 못 잡아요. CVE가 없는 신상 악성코드였으니까요. 패키지가 실제로 무엇을 하는지 보는 도구가 필요해요. Socket(네트워크 접근·셸 실행·환경변수 읽기 감지)이나 Oligo(런타임 행동 감시)가 대표적이에요.
  5. AI 에이전트 권한 묶어두기
    자율 코딩 에이전트가 의존성을 추가할 때 사람 승인을 끼워 넣으세요. Claude Code의 --permission-prompt-tool이나 Cursor의 의존성 설치 확인 프롬프트를 켜두면 됩니다. 위 3번 슬롭스쿼팅 함정이 여기서 걸러져요.
  6. 전이적 의존성 정기 감사하기
    npx socket optimize 같은 도구로 755개짜리 의존성 더미를 주기적으로 스캔하세요. 직접 고른 적 없는 패키지가 무슨 권한을 요구하는지 한 번이라도 들여다보는 게 핵심이에요.

"혹시 우리 이미 당한 거 아냐?" — 5분 점검

lockfile에서 axios@1.14.1, axios@0.30.4, plain-crypto-js@4.2.1을 검색하세요. 하나라도 나오면 즉시 안전한 버전으로 롤백하고, 아래 파일 존재 여부를 확인하세요. macOS: /Library/Caches/com.apple.act.mond · Windows: %PROGRAMDATA%\wt.exe · Linux: /tmp/ld.py. 있다면 감염을 의심하고 격리하세요.

정리하면, 이번 사건이 던지는 메시지는 단순해요. "의존성을 누가 결정하는가"가 보안의 새 전장(戰場)이라는 것. AI에게 그 결정을 통째로 맡기는 순간, 검토라는 안전장치가 사라져요. 위 6가지 중 1·2번만이라도 오늘 적용하면, 당신은 89초짜리 완전범죄의 자동 감염 경로를 닫는 거예요.