12 điểm bởi GN⁺ 24 ngày trước | 2 bình luận | Chia sẻ qua WhatsApp
  • 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
    • 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.jspackage.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

    • axios@1.14.0 (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

  1. Cố định axios về phiên bản an toàn (1.14.0 hoặc 0.30.3)
  2. Xóa thư mục plain-crypto-js rồi cài lại bằng npm install --ignore-scripts
  3. Nếu phát hiện dấu vết RAT, hãy dựng lại hệ thống
  4. Xoay vòng toàn bộ thông tin xác thực (AWS, SSH, CI/CD, v.v.)
  5. Kiểm tra pipeline CI/CD và thay khóa bí mật
  6. Dùng tùy chọn --ignore-scripts khi build tự động
  7. 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

 
chanapple 23 ngày trước

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=true vào ~/.npmrc, và chỉ riêng thiết lập này cũng đã có thể giảm nhẹ lỗ hổng
    bun và pnpm mặc định không chạy lifecycle script
    Ví dụ cấu hình cho từng package manager như sau:

    • uv: exclude-newer = "7 days"
    • npm: min-release-age=7
    • pnpm: minimum-release-age=10080
    • bun: minimumReleaseAge = 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.md hoặc CLAUDE.md
    • Có câu đùa đáp lại ý “đơn vị thời gian đều khác nhau” rằng: “Mới dùng JavaScript ngày đầu tiên à?
    • pnpm là bên triển khai tính năng này sớm nhất. npm chỉ hỗ trợ từ 11.10.0 trở lên, tức từ bản phát hành ngày 11 tháng 2 năm 2026
    • Cũng có ý kiến cho rằng nên ghi rõ đơn vị trong tên khóa cấu hình. Ví dụ như timeoutMinutes thay vì timeout
    • npm có thể không hỗ trợ comment. min-release-age=7 # days có thể sẽ không thực sự được áp dụng
    • Với yarn berry, có thể đặt npmMinimalAgeGate: "3d" trong ~/.yarnrc.yml
  • Nhiề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

    • Node.js chỉ tích hợp sẵn fetch từ v18 trở đi, và phải đến v21 mới được ổn định hóa. Axios đã tồn tại từ lâu hơn rất nhiều và vẫn được dùng rộng rãi vì có mặt trong nhiều framework lẫn tutorial
    • Trước nhận định “người dùng pnpm/bun thì an toàn”, có người đặt câu hỏi: “Vậy với các phiên bản cũ thì chẳng phải nhiều khả năng họ đã từng phê duyệt rồi sao?”
    • Cũng có câu hỏi liệu pnpm có chặn cả postinstall của dependency bậc dưới hay không
  • 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 .c duy nhất như SQLite, và cách này giúp tránh được vấn đề transitive dependency
    Phầ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

    • Package manager giờ đã trở thành yếu tố thiết yếu để một ngôn ngữ được chấp nhận. Vấn đề là thiếu kiểm soát chất lượng và cấu trúc khuyến khích phù hợp
      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
    • Cũng có ý kiến cho rằng “giải pháp đòi hỏi nỗ lực nhiều hơn một chút thì cộng đồng sẽ không chấp nhận”
      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ý
    • Trong phát triển web, bề mặt tấn công rộng hơn rất nhiều. Cách sao chép thủ công thì khó theo dõi cập nhật, nên chức năng thông báo của package manager vẫn rất hữu ích
    • Cũng có nhận định rằng riêng NPM là hệ sinh thái bị tấn công chuỗi cung ứng nghiêm trọng nhất
    • Có phản biện rằng Rust an toàn hơn C, và đa số crate đều chất lượng cao, nên quan điểm lấy thư viện C làm trung tâm là cường điệu
  • 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

    • Tuy nhiên cũng có ý kiến chỉ ra rằng cách này chỉ hiệu quả với tấn công qua postinstall. Chỉ cần require bên trong mã là vẫn có thể thực thi
    • Cũng có người làm ra sandbox cá nhân dựa trên Docker là amazing-sandbox
    • Ngoài ra còn có gợi ý dùng drop, một công cụ ở tầng cao hơn so với bwrap
    • Có ý kiến cho rằng firejail là sandbox bảo mật linh hoạt hơn
    • Cũng có người chỉ ra rằng chuyển tiếp SSH socket cho phép truy cập private key nên không có lợi ích bảo mật, và dùng khóa được bảo vệ bằng mật khẩu sẽ tốt hơn
  • Chứ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

    • Có đề xuất rằng với các gói lớn như Axios, phải có nhiều người phê duyệt MFA cùng xác nhận việc publish
    • Cũng có dự đoán rằng sẽ xuất hiện dịch vụ thương mại cung cấp dependency đã được kiểm chứng
    • Một đề xuất khác là sao chép cả test của dependency vào codebase của mình và đưa qua quy trình code review nội bộ
      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

    • Dùng zero-installs mode của Yarn
    • Tắt postinstall script hoặc kiểm tra trước khi chạy
    • Nếu mã bên thứ ba chạy trong lúc phát triển, hãy chỉ chạy trong VM/container
    • Khi thêm package, hãy xem độ phổ biến là điểm cộng, còn commit gần đây là điểm trừ, đồng thời tự kiểm tra mã và lịch sử thay đổi
    • Cần kiểm chứng toàn bộ cây dependency, và mỗi khi có lập trình viên mới được thêm vào thì phải đánh giá lại mức độ tin cậy
    • Cũng có ý kiến cho rằng chỉ cần lockfile và tùy chọn --frozen-lockfile là đã đủ an toàn
    • Có người theo triết lý đơn giản mà mạnh mẽ: “Tôi chỉ tránh những stack đầy vấn đề
  • Trướ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

    • Có đội chỉ thực hiện công việc liên quan đến NPM bên trong Apple container, và dự định chuyển cả Python lẫn Rust sang cách tương tự
      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
    • Có người nói họ thậm chí không cài Node.js/npm trên hệ thống. Từ trước đến nay họ chưa từng thấy trường hợp nào thực sự bắt buộc phải làm vậy
  • pnpm và bun giờ mặc định bỏ qua postinstall script, nhưng npm thì vẫn chạy
    Nên đặt ignore-scripts=true trong ~/.npmrc
    npm 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

    • Thiết lập thời gian phát hành tối thiểu có giúp ích, nhưng vẫn còn rất nhiều người sợ cập nhật dependency
    • Cũng có ý kiến cho rằng sự cố Trivy mới là nguyên nhân gốc rễ
    • Ngoài ra còn có đề xuất chạy trong container tạm thời rootless để giới hạn phạm vi thiệt hại