- Hai phiên bản độc hại của trình khách HTTP axios được dùng rộng rãi đã được đăng lên npm, và khi cài đặt sẽ phát tán trojan truy cập từ xa (RAT)
- Kẻ tấn công đã đánh cắp thông tin đăng nhập tài khoản maintainer để vượt qua GitHub Actions và tải gói độc hại lên theo cách thủ công
- Các phiên bản độc hại chứa phụ thuộc giả
plain-crypto-js@4.2.1, dùng script postinstall để cài RAT rồi xóa dấu vết
- RAT lây nhiễm trên cả macOS, Windows, Linux, liên lạc với máy chủ C2 (
sfrclak.com:8000) để tải thêm payload
- npm và GitHub đã nhanh chóng gỡ các phiên bản độc hại, nhưng tầm quan trọng của việc tăng cường bảo mật chuỗi cung ứng và bảo vệ thông tin xác thực một lần nữa được nhấn mạnh
Tổng quan về cuộc tấn công chuỗi cung ứng axios trên npm
- Vào ngày 31 tháng 3 năm 2026, hai phiên bản độc hại (
axios@1.14.1, axios@0.30.4) của thư viện trình khách HTTP axios được sử dụng rộng rãi đã được đăng lên npm
- Kẻ tấn công đã đánh cắp thông tin xác thực npm của maintainer chính của axios, vượt qua pipeline CI/CD GitHub Actions và đăng các gói độc hại theo cách thủ công
- Cả hai phiên bản đều chèn một phụ thuộc giả có tên
plain-crypto-js@4.2.1, và gói này cài trojan truy cập từ xa (RAT) thông qua script postinstall
- RAT nhắm tới cả macOS, Windows và Linux, liên lạc với máy chủ C2 (Command and Control) (
sfrclak.com:8000) để tải payload giai đoạn hai
- Sau khi cài đặt, mã độc xóa chính nó và các dấu vết rồi thay thế bằng
package.json sạch để né tránh phát hiện pháp y
Dòng thời gian tấn công
- 30 tháng 3, 05:57 UTC: đăng
plain-crypto-js@4.2.0 (phiên bản hợp lệ)
- 30 tháng 3, 23:59 UTC: đăng
plain-crypto-js@4.2.1 (phiên bản độc hại), thêm hook postinstall
- 31 tháng 3, 00:21 UTC: đăng
axios@1.14.1, chèn phụ thuộc độc hại
- 31 tháng 3, 01:00 UTC: đăng
axios@0.30.4, chèn cùng phụ thuộc độc hại
- 31 tháng 3, 03:15 UTC: npm xóa hai phiên bản độc hại
- 31 tháng 3, 04:26 UTC: npm thay
plain-crypto-js bằng stub security holder (0.0.1-security.0)
Tổng quan về axios
- axios là trình khách HTTP được dùng rộng rãi nhất trong hệ sinh thái JavaScript, được sử dụng cả trong Node.js lẫn trình duyệt
- Với hơn 300 triệu lượt tải mỗi tuần, chỉ một bản phát hành độc hại cũng có thể gây ra thiệt hại trên diện rộng
- Nhà phát triển thông thường khó nhận ra việc mã độc bị cài khi chạy
npm install
Các giai đoạn tấn công
-
Giai đoạn 1 — Chiếm đoạt tài khoản maintainer
- Kẻ tấn công đã chiếm tài khoản npm
jasonsaayman và đổi email thành ifstap@proton.me
- Sau đó đăng bản build độc hại lên cả nhánh phát hành 1.x và 0.x
- Các bản phát hành hợp lệ thường được xuất bản qua OIDC Trusted Publisher của GitHub Actions, nhưng
axios@1.14.1 được đăng thủ công nên không có gitHead và chữ ký OIDC
- Nhiều khả năng kẻ tấn công đã dùng token truy cập npm có thời hạn dài
-
Giai đoạn 2 — Phát tán trước phụ thuộc độc hại
plain-crypto-js@4.2.1 được đăng bằng tài khoản nrwise@proton.me
- Nó giả mạo
crypto-js, dùng cùng mô tả và URL kho lưu trữ
- Chứa hook
"postinstall": "node setup.js" để tự động chạy khi cài
- Sau cuộc tấn công,
package.md được đổi thành package.json để chuẩn bị xóa bằng chứng
-
Giai đoạn 3 — Chèn phụ thuộc vào axios
- Thêm
plain-crypto-js@^4.2.1 làm phụ thuộc runtime
- Không hề được import lần nào trong mã nguồn → phụ thuộc ma (phantom dependency)
- Khi chạy
npm install, gói sẽ tự động được cài và script postinstall được thực thi
Phân tích dropper RAT (setup.js)
-
Kỹ thuật làm rối mã
- Chuỗi được lưu mã hóa trong mảng
stq[] và được giải mã bằng _trans_1 (XOR) và _trans_2 (Base64 + đảo ngược)
- URL C2 là
http://sfrclak.com:8000/6202033
- Các chuỗi đã giải mã gồm định danh hệ điều hành (
win32, darwin), đường dẫn tệp, lệnh shell, v.v.
-
Payload theo từng nền tảng
-
macOS
- Ghi AppleScript vào
/tmp rồi chạy bằng osascript
- Tải nhị phân RAT từ C2, lưu vào
/Library/Caches/com.apple.act.mond rồi thực thi
- Tên tệp được ngụy trang như daemon hệ thống của Apple
-
Windows
- Tìm đường dẫn PowerShell rồi sao chép thành
%PROGRAMDATA%\\wt.exe
- Dùng VBScript để tải và chạy RAT PowerShell từ C2
- Các tệp tạm (
.vbs, .ps1) bị xóa sau khi thực thi
-
Linux
- Dùng
curl để tải /tmp/ld.py, sau đó chạy bằng nohup python3
- Tệp
/tmp/ld.py vẫn còn tồn tại
- Trên cả ba nền tảng, phần thân POST
packages.npm.org/product0~2 được dùng để ngụy trang thành lưu lượng npm hợp lệ
-
Tự xóa và che giấu
- Xóa
setup.js và package.json
- Đổi
package.md thành package.json để ngụy trang thành gói bình thường
- Sau đó, việc phát hiện qua
npm audit hoặc kiểm tra thủ công gần như không thể
- Tuy vậy, chỉ riêng sự tồn tại của
node_modules/plain-crypto-js/ đã là bằng chứng nhiễm mã độc
Xác minh thực thi bằng StepSecurity Harden-Runner
- Harden-Runner ghi lại sự kiện mạng, tiến trình và tệp theo thời gian thực trong GitHub Actions
- Khi cài
axios@1.14.1, phát hiện hai lần kết nối đến C2 (curl, nohup)
- Kết nối đầu tiên xảy ra sau 2 giây kể từ khi bắt đầu
npm install
- Kết nối thứ hai xảy ra sau 36 giây và tiếp tục chạy dưới dạng tiến trình nền
- Phân tích cây tiến trình cho thấy tiến trình
nohup trở thành tiến trình mồ côi dưới PID 1 (init), xác nhận tiếp tục chạy dai dẳng
- Nhật ký sự kiện tệp cho thấy
package.json bị ghi đè hai lần
- Lần thứ nhất: ghi phiên bản độc hại trong lúc cài đặt
- Lần thứ hai: sau 36 giây, bị thay bằng stub sạch
Chỉ dấu xâm nhập (IOC)
-
Gói npm độc hại
- axios@1.14.1 · shasum: 2553649f232204966871cea80a5d0d6adc700ca
- axios@0.30.4 · shasum: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
- plain-crypto-js@4.2.1 · shasum: 07d889e2dadce6f3910dcbc253317d28ca61c766
-
Mạng
-
Đường dẫn tệp
- macOS:
/Library/Caches/com.apple.act.mond
- Windows:
%PROGRAMDATA%\\wt.exe
- Linux:
/tmp/ld.py
-
Tài khoản kẻ tấn công
jasonsaayman (maintainer bị chiếm đoạt)
nrwise (tài khoản do kẻ tấn công tạo)
-
Phiên bản an toàn
Quy trình kiểm tra ảnh hưởng và ứng phó
- Kiểm tra 1.14.1 / 0.30.4 trong
npm list axios hoặc package-lock.json
- Kiểm tra sự tồn tại của
node_modules/plain-crypto-js
- Nếu có tệp RAT theo từng hệ điều hành, hãy xem như hệ thống đã bị xâm nhập hoàn toàn
- Kiểm tra lịch sử cài các phiên bản đó trong log CI/CD rồi thay toàn bộ khóa bí mật và token
Các bước khôi phục
- Cố định axios về phiên bản an toàn (1.14.0 hoặc 0.30.3)
- Xóa thư mục
plain-crypto-js rồi cài lại bằng npm install --ignore-scripts
- Nếu phát hiện dấu vết RAT, hãy dựng lại hệ thống
- Xoay vòng toàn bộ thông tin xác thực (AWS, SSH, CI/CD, v.v.)
- Kiểm tra pipeline CI/CD và thay khóa bí mật
- Dùng tùy chọn
--ignore-scripts khi build tự động
- Chặn miền/IP C2 bằng firewall hoặc
/etc/hosts
Các tính năng của StepSecurity Enterprise
-
Harden-Runner
- Áp dụng whitelist lưu lượng mạng đi ra trong GitHub Actions
- Chặn lưu lượng bất thường và ghi log
- Có thể chặn trước kết nối tới
sfrclak.com:8000
-
Dev Machine Guard
- Giám sát theo thời gian thực các gói npm được cài trên máy nhà phát triển
- Phát hiện ngay các thiết bị đã cài
axios@1.14.1, 0.30.4
-
npm Package Cooldown Check
- Áp dụng thời gian chặn cài tạm thời cho các gói mới được đăng
- Có thể phát hiện các bản đăng độc hại nhanh như
plain-crypto-js@4.2.1
-
Compromised Updates Check
- Chặn hợp nhất PR dựa trên cơ sở dữ liệu gói độc hại theo thời gian thực
axios@1.14.1, plain-crypto-js@4.2.1 được đăng ký ngay lập tức
-
Package Search
- Tìm vị trí đưa một gói cụ thể vào trên toàn bộ PR và kho lưu trữ trong tổ chức
- Xác định ngay phạm vi ảnh hưởng (repository, team, PR)
-
AI Package Analyst
- Giám sát npm registry theo thời gian thực và phát hiện mã độc dựa trên hành vi
- Cả hai phiên bản độc hại đều được phát hiện chỉ vài phút sau khi đăng
-
Threat Center Alert
- Cung cấp cảnh báo threat intel bao gồm tóm tắt cuộc tấn công, IOC và quy trình ứng phó
- Đảm bảo khả năng quan sát theo thời gian thực thông qua tích hợp SIEM
Lời cảm ơn
- Maintainer axios và cộng đồng đã ứng phó nhanh chóng qua GitHub issue #10604
- GitHub đã đình chỉ tài khoản bị xâm phạm và npm đã xóa các phiên bản độc hại cũng như áp dụng security holder
- Sự phối hợp giữa maintainer, GitHub và npm đã giúp giảm thiểu thiệt hại cho nhà phát triển trên toàn thế giới
2 bình luận
Tôi chưa từng nghĩ một gói có quy mô như thế này lại có thể bị xâm phạm, nhưng axios còn vượt ngoài sức tưởng tượng.
Ý kiến Hacker News
npm, bun, pnpm, uv hiện đều đã hỗ trợ thiết lập thời gian phát hành tối thiểu của gói
Tôi đã thêm
ignore-scripts=truevào~/.npmrc, và chỉ riêng thiết lập này cũng đã có thể giảm nhẹ lỗ hổngbun và pnpm mặc định không chạy lifecycle script
Ví dụ cấu hình cho từng package manager như sau:
exclude-newer = "7 days"min-release-age=7minimum-release-age=10080minimumReleaseAge = 604800Điều thú vị là mỗi bên lại dùng đơn vị thời gian khác nhau
Nếu dùng agent LLM, thiết lập này có thể gây ra lỗi, nên cần thêm hướng dẫn liên quan vào
AGENTS.mdhoặcCLAUDE.mdtimeoutMinutesthay vìtimeoutmin-release-age=7 # dayscó thể sẽ không thực sự được áp dụngnpmMinimalAgeGate: "3d"trong~/.yarnrc.ymlNhiều người bị sốc khi nghe tin Axios đã bị phơi nhiễm bởi tấn công chuỗi cung ứng
Bản thân Axios không chứa mã độc, nhưng nó đã bị chèn thêm dependency giả
plain-crypto-js@4.2.1, dependency này chạy postinstall script để cài RAT (trojan truy cập từ xa)Đây là tin may mắn đối với người dùng phải tự tay phê duyệt postinstall script như pnpm hay bun
Có ý kiến cho rằng package manager là một thí nghiệm thất bại
Có những thư viện C chất lượng cao được đóng gói thành một file
.cduy nhất như SQLite, và cách này giúp tránh được vấn đề transitive dependencyPhần lớn bề mặt tấn công phát sinh từ các phụ thuộc gián tiếp như vậy
Ngay cả OpenSSL cũng đang được viết lại vì vấn đề chất lượng mã, còn JS thì khó mở rộng standard library nên tình trạng polyfill tràn lan rất nghiêm trọng
Thay vào đó, có đề xuất siết chặt tiêu chuẩn chất lượng trên các kho như npm và chỉ cho phép những maintainer có trách nhiệm được đăng ký
Có người đùa rằng họ bắt đầu ngày mới bằng lời chào tự giễu: “Hôm nay lại là gói npm nào bị hack đây?”
Với người dùng Linux, có khuyến nghị dùng bwrap để sandbox hóa toàn bộ logic build như npm, pip, cargo, gradle
bwrap cung cấp môi trường cô lập giống Docker nhưng không cần image. Flatpak cũng dựa trên cùng công nghệ
Khi triển khai lên server, hardening container là quan trọng, và mấu chốt là phải coi môi trường CI/CD như vùng không đáng tin cậy
Khi chạy AI, cũng nên dùng cùng kiểu sandbox này
requirebên trong mã là vẫn có thể thực thiChứng kiến vấn đề dependency lặp đi lặp lại khiến nhiều người lo hệ sinh thái Rust rồi cũng sẽ gặp chuyện tương tự
Dù rất khó làm standard library phình to, vẫn cần một cơ chế bảo đảm chất lượng gói đáng tin cậy
Nhờ AI mà loại công việc bổ sung này nay đã khả thi hơn, và cũng có sự tự nhìn nhận rằng lẽ ra từ trước đã nên làm như vậy
Các nguyên tắc cốt lõi để giảm thiểu phơi nhiễm trước tấn công chuỗi cung ứng NPM
--frozen-lockfilelà đã đủ an toànTrước câu hỏi “phải làm sao để tránh hoàn toàn kiểu tấn công này?”,
có ý kiến muốn chuyển sang Qubes OS để tách biệt hoàn toàn password manager với môi trường build
Họ ví điều này như đồ bảo hộ trong phòng thí nghiệm hóa học (PPE): môi trường phát triển cũng cần cô lập và bảo vệ
pip cũng đã bắt đầu chặn cài đặt bên ngoài virtualenv, và người ta kỳ vọng sau này package manager sẽ có tùy chọn từ chối chạy ngoài sandbox
pnpm và bun giờ mặc định bỏ qua postinstall script, nhưng npm thì vẫn chạy
Nên đặt
ignore-scripts=truetrong~/.npmrcnpm vẫn đang ghi nhận 80 triệu lượt tải mỗi tuần
Có suy đoán rằng vụ rò rỉ thông tin xác thực lần này nhiều khả năng bắt nguồn từ sự cố LiteLLM trước đó
Dù việc dùng Python hay Node.js khiến người ta thấy bất an, cảm giác đây thực ra là vấn đề mang tính phổ quát