2026년 4월 1일, 이 보고서는 다수의 중간 신뢰도 정황이 겹친 결과를 반영하여 이번 침해가 금전적 동기를 가진 북한 국가 후원 위협 행위자 UNC1069에 의해 수행되었을 가능성이 높음을 명시하도록 업데이트되었습니다.
2026년 3월 31일, 공격자들은 Axios의 주요 유지관리자의 취약한 npm 계정을 이용하여 레지스트리에 패키지의 두 가지 악성 버전을 배포했습니다. 취약한 릴리스에는 크로스 플랫폼 드로퍼(dropper)가 포함된 새로운 의존성이 포함되어 있었으며, 이 드로퍼는 패키지를 npm을 통해 설치한 모든 머신에 플랫폼별 원격 접근 트로이목마(RAT)를 다운로드하고 배포했습니다. 드로퍼는 하드코딩된 명령제어(C2) 서버와 통신하며 macOS, Windows, Linux용 플랫폼별 페이로드를 다운로드한 뒤, 패키지 내 악성 내용과 자신에 대한 모든 증거를 디스크에서 삭제하고 배포된 RAT만 남깁니다.
Axios란?
Axios는 JavaScript 생태계에서 가장 널리 사용되는 HTTP 클라이언트 라이브러리입니다. 프론트엔드 프레임워크, 백엔드 서비스, CI/CD 툴링, 기업 내부 애플리케이션 등 Node.js 또는 브라우저에서 HTTP 요청을 처리하는 거의 모든 프로젝트에서 Axios가 사용될 가능성이 높습니다. package.json에서 ^1.14.0과 같은 표준 캐럿 범위를 사용하는 프로젝트는 다음 설치 시 아무런 변경 사항 없이 자동으로 악성 버전으로 설치될 수 있으며, 패키지 이름, 배포자, 버전 번호로는 문제를 확인할 수 없습니다.
Axios는 주간 다운로드 수가 1억 회 이상이며, HTTP 요청을 수행하는 거의 모든 Node.js 애플리케이션의 의존성 트리에 포함되어 있어, 이번 침해 사건의 영향력이 매우 클 수 있습니다.
어떻게 발견되었나요?
Socket Security의 자동 스캐너는 배포 6분 만에 악성 의존성 plain-crypto-js@4.2.1을 탐지했습니다. StepSecurity는 독립적으로 두 가지 취약한 Axios 버전을 확인하고 전체 기술 분석을 발표했으며, 런타임 분석을 통해 악성 코드가 npm 설치 시작 1.1초 만에 첫 번째 C2 콜백을 수행했음을 확인했습니다.
Socket 공동 창립자 Feross Aboukhadijeh는 공개 경고를 게시했습니다:
"Axios에 대한 적극적인 공급망 공격 – npm에서 가장 많이 의존되는 패키지 중 하나입니다. 전형적인 공급망 설치형 악성코드 사례입니다."
npm 보안팀은 두 가지 악성 버전을 모두 제거하고 보안용 스텁(Stub)으로 교체했습니다. axios@1.14.1은 약 3시간 동안 배포되었으며, axios@0.30.4는 약 2시간 15분 동안 배포되었습니다. 이 기간 동안 정식 유지관리자인 Jason Saayman은 자신의 계정에 접근할 수 없었고, Axios 협력자가 GitHub에서 공격자의 접근 권한이 자신의 권한을 초과해 공격자를 차단할 수 없다고 보고했습니다.
기술적 분석
영향을 받은 버전
취약한 릴리스는 axios@1.14.1과 axios@0.30.4입니다. 현대 1.x 브랜치와 이전 0.x 브랜치가 각각 39분 간격으로 모두 공격당했습니다. 안전하게 고정(pinning)할 수 있는 버전은 axios@1.14.0과 axios@0.30.3입니다. Socket은 또한 동일한 페이로드를 배포하는 두 개의 추가 패키지를 확인했습니다: @shadanai/openclaw와 @qqbrowser/openclaw-qbot@0.0.130, 이들은 벤더 의존성을 통해 배포되었습니다.
공격 전개 과정
공격자는 Axios의 주요 유지관리자인 jasonsaayman npm 계정을 탈취하고, 등록된 이메일을 익명 ProtonMail 주소로 변경한 뒤, npm CLI를 통해 두 가지 악성 버전을 직접 배포했습니다. 이 과정에서 Axios 프로젝트의 정상 GitHub Actions 파이프라인은 완전히 우회되었습니다. 두 버전 모두 Axios GitHub 저장소에는 해당하는 커밋, 태그, 릴리스가 존재하지 않습니다.
Axios 침해 18시간 전, 임시 계정(nrwise, 역시 ProtonMail 사용)이 plain-crypto-js@4.2.0을 게시했습니다. 이는 합법적인 crypto-js 라이브러리의 클린 복사본으로, npm 게시 기록(history)을 쌓고 제로 히스토리 스캐너 플래그를 피하기 위해 사용되었습니다.
2026년 3월 30일 23:59 UTC, 공격자는 난독화된 드로퍼 페이로드와 실행 후 증거 삭제를 위한 사전 준비된 깨끗한 package.json 스텁을 포함한 plain-crypto-js@4.2.1을 게시했습니다.
22분 후, axios@1.14.1이 배포되었고, 단 하나의 새로운 의존성 "plain-crypto-js": "^4.2.1"이 추가되었습니다. 이 패키지는 Axios 코드베이스 어디에서도 참조되지 않았으며, 오직 npm postinstall 훅을 트리거하기 위해 존재했습니다.
익스플로잇 흐름
드로퍼(setup.js)는 이중 난독화(문자열 역순 + Base64, XOR 복호화)를 사용하여 모든 민감 문자열을 저장 시 숨기고, 런타임에서만 복호화합니다. 또한 동적으로 child_process, os, fs를 가져와 정적 분석 탐지를 회피하며, 대상 운영체제(OS)에 따라 분기합니다.
- npm은 취약한 Axios 버전의 의존성으로
plain-crypto-js@4.2.1을 자동 설치합니다. - postinstall 훅이 실행되어 npm 설치가 끝나기 전에
node setup.js가 실행됩니다. - 드로퍼는
os.platform()으로 OS를 확인하고, C2 서버sfrclak[.]com:8000과 통신하며, POST 본문에 npm 레지스트리 URL로 위장된 플랫폼 식별자를 전달합니다. - 플랫폼별 RAT 배포:
- macOS: AppleScript가
/Library/Caches/com.apple.act.mond에 바이너리를 다운로드하고 실행 권한을 부여한 뒤/bin/zsh로 실행합니다. (Apple 데몬 이름을 모방) - Windows: 합법적
powershell.exe를%PROGRAMDATA%\wt.exe로 복사하고, 숨겨진 VBScript/PowerShell 체인을 실행하여 RAT를 다운로드하고-ExecutionPolicy Bypass로 실행합니다. - Linux:
curl이 Python RAT를/tmp/ld.py로 다운로드하고nohup python3로 부모 프로세스 종료 후에도 실행되도록 합니다. - 자기 파괴: 드로퍼는
setup.js를 삭제하고, postinstall 훅이 포함된 package.json을 제거하며, 사전 준비된 깨끗한 스텁으로 교체합니다. 감염 후node_modules/plain-crypto-js/를 확인해도 의심스러운 내용은 남아 있지 않습니다.
StepSecurity의 전체 정적 및 런타임 분석(드로퍼 문자열 디코딩, Harden-Runner 프로세스 트리 포함)은 https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan 에서 확인할 수 있습니다.
Socket의 분석은 https://socket.dev/blog/axios-npm-package-compromised 에서 확인 가능합니다.
RAT의 중요한 특징은 지속성 메커니즘이 없습니다. 감염된 장치를 재부팅하면 바이너리는 디스크에 남아 있지만 실행되지 않습니다. 이는 공격자가 EDR 및 방어자에게 RAT가 더 쉽게 탐지되는 것을 피하기 위해 의도했을 수 있습니다. 또는 RAT가 C2 서버와 연결하여 2차 페이로드를 가져오거나 명령을 받아 지속성을 설정하도록 설계되었을 수도 있습니다. 공격자는 지속성 기능을 의도된 대상이나 고가치 피해자에게만 예약했을 가능성도 있습니다. 일부 보고서에서는 Windows에서 지속성 메커니즘이 확인되었지만, 이는 감염 후 C2 명령으로 생성된 것인지, 초기 일반 감염 과정에서 변경된 것인지 명확하지 않습니다.
공격 주체 및 목적
2026년 4월 1일 업데이트: 이번 침해는 금전적 동기를 가진 북한 국가 지원 위협 행위자(DPRK state sponsored threat actor) UNC1069에 의해 수행되었을 가능성이 높습니다. 이러한 배후 추정은 이전 UNC1069 활동과의 다수의 중간 신뢰도 정렬에 기반합니다. 예를 들어:
멀웨
- C2 URL이 명령줄에서 동적으로 제공됨
- 비콘(beacon) 전송 시 사용된 드문 사용자 에이전트 문자열 동일
- macOS에서 사용된 임시 디렉터리 위치 동일
C2
- Axios C2 주소로의 연결이 이전에 UNC1069가 사용한 Astrill VPN 노드에서 관찰됨
- Axios C2 주소와 동일 ASN 내 인접 인프라가 과거 UNC1069와 연관 있음
RAT 기능은 초기 단계 RAT로 예상되는 일반적이고 다용도의 기능을 가지며, 하드코딩된 명령은 다음과 같습니다:
- 자기 제거(Self-removal)
- 바이너리 다운로드 및 실행
- 스크립트 및 명령 실행
- 디렉터리 열거(하드코딩 대상:
/home/user/.ssh및/etc/passwd)
RAT 기능은 어느 공격자에게나 유용할 수 있으며, 특정 악성 기능(예: 암호화폐 채굴, 자격 증명 탈취)을 포함하지 않아 EDR에 의해 탐지될 가능성이 낮습니다. 패키지 침해는 빠르게 이루어졌으며, 수행된 행동은 비교적 은밀했습니다. 그러나 이러한 특성만으로 공격자가 국가 주체인지, 금전적 동기 공격자인지 특정할 수는 없으며, 유지관리자의 계정에 접근할 수 있는 누구든 이 공격을 수행할 수 있습니다.
영향 여부 확인 방법
- lockfile에서
axios@1.14.1,axios@0.30.4, 또는plain-crypto-js참조 여부를 확인합니다.node_modules/plain-crypto-js/가 존재하는 프로젝트가 있다면, 해당 머신에서 드로퍼가 실행된 것입니다. (단, 드로퍼의 자체 정리 루틴 때문에 내용은 무해한 스텁으로 대체되었을 수 있습니다.)
- 플랫폼별 경로에서 RAT 흔적을 확인합니다.
- macOS:
/Library/Caches/com.apple.act.mond - Windows:
%PROGRAMDATA%\wt.exe - Linux:
/tmp/ld.py - 드로퍼의 자기 정리 때문에 이미 삭제되었을 수도 있습니다.
- macOS:
- 네트워크 텔레메트리에서
sfrclak[.]com또는142.11.206.73의 포트 8000으로 향하는 아웃바운드 연결을 확인합니다.- 파일시스템 흔적은 삭제되지만, 네트워크 로그는 남으므로 가장 신뢰할 수 있는 지표입니다.
- 3월 31일 UTC 기준 약 00:21~03:15 사이에 npm install이 실행된 CI/CD 파이프라인을 감사합니다.
- 이 시간 동안 워크플로우가 주입된 비밀값과 배포 키에 접근했을 수 있습니다.
영향을 받았다고 의심될 경우
axios@1.14.0 또는 axios@0.30.3로 다운그레이드하고, node_modules/plain-crypto-js를 제거한 후 npm install --ignore-scripts로 재설치합니다.
(RAT 흔적이 발견되면 시스템이 완전히 침해된 것으로 간주하고, 신뢰할 수 있는 이미지에서 재구축합니다.)
취약 머신에서 접근 가능한 모든 자격증명을 교체합니다. (저장된 비밀번호, npm 또는 기타 토큰, SSH 키, 클라우드 액세스 키, .env 내용, CI/CD 비밀값 포함_
방화벽 및 DNS 계층에서 sfrclak[.]com과 142.11.206.73을 차단합니다.
귀사의 공급망 강화 방법
- 의존성 버전을 정확히 고정하고 lockfile을 커밋하여 관리합니다. 캐럿 범위가 악성 버전으로 자동 해석되는 원인이 되었으므로, CI/CD에서는 npm ci를 사용하여 lockfile에 명시된 버전만 설치되도록 합니다.
- 자동화된 빌드에서 postinstall 스크립트를 비활성화합니다(npm ci --ignore-scripts). 이번 공격 체인은 npm postinstall 라이프사이클 훅에 의존하며, 대부분의 패키지는 postinstall이 필요하지 않습니다.
- 패키지 최소 배포 기간(minimum package age)을 적용합니다. 예를 들어, .npmrc에 min-release-age=7을 설정합니다. Aikido의 Safe Chain과 같은 도구를 사용해 설정된 쿨다운 기간 내 배포된 패키지를 차단할 수도 있습니다. 이번 악성 plain-crypto-js@4.2.1 패키지는 배포 24시간도 되지 않았으며, 48시간 기준의 패키지 연령 제한만 있어도 공격을 예방할 수 있었습니다.
- CI/CD 러너에서 외부 트래픽을 제어합니다. 드로퍼는 설치 후 1.1초 만에 C2 서버와 통신하므로, 러너가 무제한 아웃바운드 연결을 허용하면 postinstall 스크립트가 모든 C2 서버와 연결될 수 있습니다.
익숙한 패턴
Axios 침해 사건은 지난 1년간 주요 npm 공급망 공격과 동일한 패턴을 따릅니다. 유지관리자 계정 탈취, 의존성 매니페스트(manifest)에 작은 변경, self-deleting 페이로드를 실행하는 postinstall 훅이 그 예입니다.
예를 들어, 2025년 9월에는 피싱으로 탈취된 자격증명으로 Chalk와 Debug가 침해되었고, 같은 달 Shai-Hulud 웜이 역사상 최초의 웜 가능 npm 악성코드로 등장했습니다. 12월에는 두 번째 변종이 약 40만 개 개발자 비밀을 수집했습니다.
npm은 최근 필수 FIDO 2FA, 자동화 토큰 기본 비활성화, 신뢰된 게시 강제 등 보안 개선을 계획했으나, 아직 개발 중입니다. 따라서 현재는 제3자 도구와 개발자의 인식이 npm이 놓친 부분을 감지하는 데 중요합니다.
지원이 필요하신가요?
귀사의 조직이 이번 사건으로 영향을 받았다고 의심되거나, 다음 공격 전에 공급망 노출을 평가하고 싶다면, LRQA가 지원할 수 있습니다.
침해 지표 (IOCs)
|
Network |
|
|
C2 domain - hxxp |
//sfrclak[.]com:8000 |
|
C2 IP |
142.11.206.73:8000 |
|
C2 URL |
hxxp:////sfrclak[.]com:8000/6202033 |
|
User-Agent string |
mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0) |
|
Mac C2 payload retrieval POST body |
packages.npm.org/product0 |
|
Windows C2 payload retrieval POST body |
packages.npm.org/product1 |
|
Linux C2 payload retrieval POST body |
packages.npm.org/product2 |
|
Mac Host |
|
|
MacOS temporary file (deleted after use) |
/tmp/6202033 |
|
MacOS RAT binary file |
/Library/Caches/com.apple.act.mond |
|
Injected binaries from RAT activity |
/private/tmp/.[XXXXXX] |
|
Mac RAT SHA256 |
92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a |
|
Mac RAT SHA1 |
13ab317c5dcab9af2d1bdb22118b9f09f8a4038e |
|
Mac RAT MD5 |
7a9ddef00f69477b96252ca234fcbeeb |
|
Windows Host |
|
|
Copies powershell.exe to |
%PROGRAMDATA%\wt.exe |
|
VBS wrapper, deleted after use |
%TEMP%\6202033.vbs |
|
Powershell payload, deleted after use |
%TEMP%\6202033.ps1 |
|
Linux Host |
|
|
Linux temporary file |
/tmp/ld.py |
|
NPM Packages |
|
|
axios@1.14.1 shasum |
2553649f232204966871cea80a5d0d6adc700ca |
|
axios@0.30.4 shasum |
d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71 |
|
plain-crypto-js@4.2.1 shasum |
07d889e2dadce6f3910dcbc253317d28ca61c766 |
|
Post compromise activity |
After payload execution, the dropper removes any indication of the malicious code from the package directory by deleting setup.js and package.json, replacing package.json with a legitimate/clean file. |
|
Notable strings |
|
|
XOR key - OrDeR_7077 |
|
|
XOR constant - 333 |
|
|
Campaign id |
6202033 |
|
Plain-crypto-js@4.2.0 publisher |
nrwise@proton.me |
|
Attacker controlled email address used in axios maintainer account hijack |
ifstap@proton.me |
|
Attacker controlled email address used to publish plain-crypto-js |
nrwise@proton.me |
|
Npm audit commands |
|
|
Check for existence of plain-crypto-js |
npm ls plain-crypto-js |
|
Check for existence of plain-crypto-js |
cat package-lock.json | grep -A3 "plain-crypto-js" |
|
Check for existence of malicious axios versions |
grep -E '"axios".*"(1\.14\.1|0\.30\.4)"' package-lock.json |
