1 điểm bởi GN⁺ 2025-09-09 | 2 bình luận | Chia sẻ qua WhatsApp
  • Ngày 8 tháng 9, phát hiện mã độc bị chèn vào các gói npm phổ biến
  • Tổng cộng có 18 gói bị ảnh hưởng, với hơn 2 tỷ lượt tải mỗi tuần trên toàn thế giới
  • Kẻ tấn công đã chèn mã có khả năng âm thầm chặn các hoạt động tiền mã hóa và Web3 trong trình duyệt của khách truy cập website, đồng thời chuyển hướng các phê duyệt và luồng tiền trong ví sang tài khoản của kẻ tấn công
  • Xác nhận rằng mã JavaScript bị làm rối đã được thêm vào tệp gói chính (index.js)
  • Sự việc bắt đầu đồng thời với các bản cập nhật của những gói bị nhắm mục tiêu, và cộng đồng hiện đang ứng phó

Tổng quan sự cố

  • Tính đến 13:16 UTC ngày 8 tháng 9, feed giám sát bảo mật của Aikido đã phát hiện nhiều gói chứa mã độc được tải lên npm
  • Các gói này rất phổ biến trên npm, ghi nhận hơn 2 tỷ lượt tải mỗi tuần

Phương thức và nội dung tấn công

  • Sau bản cập nhật độc hại, xác nhận có cơ chế thực thi bí mật mã độc JavaScript trong trình duyệt của khách truy cập trên các website sử dụng các gói đó
    • Mục tiêu của mã này là giám sát hoạt động tiền mã hóa và Web3, can thiệp vào tương tác với ví, và tự ý thay đổi địa chỉ nhận thanh toán
    • Người dùng có thể bị chuyển tiền và quyền phê duyệt đến địa chỉ tiền mã hóa do kẻ tấn công chỉ định mà không thấy thay đổi đặc biệt nào trên màn hình

Phân tích chi tiết mã độc

  • Điển hình như trong is-arrayish, tệp index.js đã bị chỉnh sửa để chèn JavaScript phức tạp bị làm rối
  • Trong mã, giao diện window.ethereum được sử dụng để kiểm tra thông tin tài khoản ví và xác minh điều kiện kích hoạt mã tấn công
  • Bên trong có nhiều địa chỉ tiền mã hóa (Bitcoin, Ethereum, v.v.) và logic hàm, với chức năng thay thế địa chỉ ví và chi tiết giao dịch bằng địa chỉ của kẻ tấn công
  • Điều này tạo ra rủi ro tài sản tiền mã hóa của người dùng thực bị rò rỉ và chuyển đi trái phép mà không hề hay biết

Tình hình hiện tại và phản ứng của cộng đồng

  • Các phiên bản gói độc hại đang được gỡ bỏ nhanh chóng khỏi các kho npm chính
  • Trong cộng đồng IT/mã nguồn mở, các hoạt động như khuyến cáo ngừng sử dụng và nâng cấp các gói liên quan, phát hiện thêm lây nhiễm và thực hiện biện pháp xử lý đang được triển khai mạnh mẽ
  • Vụ hack này đang trở thành lời cảnh tỉnh lớn hơn về bảo mật chuỗi cung ứng gói, phát hiện mã bị làm rối, và bảo vệ tiện ích mở rộng trình duyệt Web3

2 bình luận

 
crawler 2025-09-09

> Ngày 8 tháng 9 năm 2023,

Do bị ảo giác nên ngày tháng đã bị ghi sai. Không phải chuyện của năm 2023 mà là chuyện bây giờ.
Có vẻ như tin npm bị hack xuất hiện khá thường xuyên. Trông có vẻ đang có vấn đề.

 
GN⁺ 2025-09-09
Ý kiến Hacker News
  • Vâng, tôi là người đã bị hack. Thật sự rất xấu hổ và xin lỗi tất cả mọi người. Mong mọi người xem chi tiết tại đâytại đây. Tôi đã đăng danh sách các package bị ảnh hưởng. Có vẻ đây là một cuộc tấn công có chủ đích. Tôi sẽ tiếp tục cập nhật cho đến khi hết thời gian có thể sửa bình luận. Package Chalk đã được khôi phục, nhưng những package còn lại vẫn đang bị chiếm quyền (ngày 8 lúc 17:50 CEST). NPM vẫn chưa có phản hồi nào. Tài khoản NPM của tôi hiện không thể truy cập, và chức năng khôi phục mật khẩu cũng không hoạt động. Lúc này tôi chỉ có thể chờ. Email từ bộ phận hỗ trợ đến từ npmjs dot help và trông rất thuyết phục. Đây không phải lời biện minh, nhưng đó là một buổi sáng mệt mỏi, tôi chỉ định xử lý nhanh thêm một việc nên đã bất cẩn bấm vào liên kết thay vì như thường lệ là truy cập trực tiếp trang chính thức trước (có lẽ vì lúc đó đang dùng điện thoại). Cuộc tấn công này chỉ ảnh hưởng đến NPM, và tôi sẽ tiếp tục cập nhật ở /debug-js. Một lần nữa, thật sự xin lỗi

    • Cách bạn phản ứng nhanh chóng và minh bạch trong một tình huống căng thẳng như thế này thực sự là hình mẫu đáng noi theo. Tôi nghĩ mình sẽ không bị lừa bởi phishing nữa, nhưng xin bổ sung vài mẹo: 1) tuyệt đối đừng đăng nhập qua liên kết trong email. Email phishing và email thật quá khó phân biệt, nên cách duy nhất để không mắc bẫy là hoàn toàn không thử. 2) dùng khóa bảo mật U2F/Webauthn làm xác thực hai yếu tố thì gần như hoàn hảo để chống phishing. TOTP thì không được như vậy. Cuối cùng thì con người lúc mệt hoặc bận vẫn luôn có thể mắc sai lầm. Lần này chỉ là bạn không may trở thành mục tiêu. Một lần nữa, bạn đã xử lý rất tốt

    • Theo hướng dẫn của sindresorhus, có thể kiểm tra xem cây phụ thuộc của mình có mã độc hay không bằng lệnh sau: rg -u --max-columns=80 _0x112fa8 (cần ripgrep, cài bằng brew install rg). Cũng nên xem bình luận gốc

    • Hồi còn học đại học tôi từng bị phishing khi say rượu (chuyện cũng lâu rồi). Bất kỳ ai cũng có thể trở thành nạn nhân. Nhưng điều đáng ngạc nhiên là phản ứng của NPM lại chậm như vậy. Tôi nghĩ điều này sẽ càng có lợi cho kẻ tấn công

    • Socket đã phát hiện vụ việc này gần như ngay lập tức. Họ cũng có viết trong bài blog liên quan. Dù vụ này rất đáng tiếc, tôi vẫn đánh giá cao việc hệ sinh thái mã nguồn mở đã phản ứng cực kỳ nhanh. Những sự cố như thế này lại một lần nữa cho thấy vì sao việc quét package là quan trọng

    • Cảm ơn vì đã cảnh báo sớm. Tôi đã gửi email cho porkbun để yêu cầu chặn tên miền

  • Có một phần rất tinh vi trong payload mã độc này mà chưa được chú ý đúng mức. Đó là thay vì thay ngẫu nhiên địa chỉ ví, nó tính khoảng cách Levenshtein giữa địa chỉ hợp lệ và từng địa chỉ trong danh sách của kẻ tấn công rồi chọn ví của kẻ tấn công giống nhất. Nói cách khác, nó được thiết kế để vượt qua thói quen bảo mật phổ biến là chỉ kiểm tra qua loa phần đầu và cuối địa chỉ. Có một bài viết phân tích chi tiết đã deobfuscate toàn bộ payload và phân tích cả tính năng bất thường này. Mọi người hãy cẩn thận

    • Có một chỗ trong bài khiến tôi hơi bối rối, vì tôi hiểu rằng package-lock.json dùng để ghim "chính xác" một phiên bản cụ thể. package.json thì có thể khai báo kiểu "từ phiên bản x trở lên", nhưng trong lockfile lại ghi trực tiếp phiên bản được chọn và URL tarball của từng dependency. Khi có lockfile thì trong môi trường CI lẽ ra package không tự động được cập nhật; không biết có phải tôi đang hiểu sai cách lockfile của npm/yarn/pnpm hoạt động không. Cũng nên tham khảo trích dẫn từ tài liệu chính thức của npm

    • Tôi nghĩ nếu hiển thị giá trị hash bằng màu cho từng ký tự (màu chữ/nền được quyết định theo hash và chỉ số ký tự) thì sẽ dễ phân biệt hơn nhiều giữa các hash bị làm cho trông na ná nhau bằng mắt thường

    • Không biết có thông tin nào cho thấy kỹ thuật này có liên quan đến một nhóm hacker cụ thể nào không

    • Đoạn mã tấn công này đúng là khéo léo, nhưng thực ra web đã phải chống lại các cuộc tấn công địa chỉ tương tự suốt hàng chục năm, và đây chỉ là một phiên bản động hơn của cùng ý tưởng đó. Tôi không đồng ý với việc thổi phồng nó quá mức. Thành thật mà nói, cả bài phân tích này còn cho tôi cảm giác như do AI viết, nên không thấy đây là một phân tích thật sự cẩn trọng

  • Tôi đã để lại một bình luận tương tự khi Nx gặp y hệt chuyện này 12 ngày trước. Đây không phải thất bại của một cá nhân, mà là thất bại của cả ngành. Các cuộc tấn công chuỗi cung ứng có tác động cực lớn, trong khi theo tôi thì về cơ bản đây là những vấn đề đã có cách giải quyết từ lâu. Vì chúng ta là nhà phát triển phần mềm, chỉ cần áp dụng rộng rãi các biện pháp bảo mật tiêu chuẩn như ký mã, ký artifact, phát hiện hành vi tài khoản bất thường, 2FA, v.v. là có thể ngăn chặn. Việc các nền tảng đóng gói phần mềm vẫn chưa làm là không phải do giới hạn kỹ thuật, mà vì không ai bắt buộc họ làm. Với sự phát triển của AI và việc các cuộc tấn công ngoài thực tế liên tục thành công, chuyện này sẽ còn nghiêm trọng hơn. Tôi nghĩ đã đến lúc phải bắt buộc áp dụng các tiêu chuẩn bảo mật mạnh

    • Những biện pháp bảo mật này luôn có đánh đổi. Ví dụ, nếu áp dụng các cơ chế heuristic hay dựa trên chứng thực, khá nhiều hệ thống tự động hóa hoặc người dùng phổ thông có thể bị loại khỏi cuộc chơi. 2FA qua SMS thì yếu về mặt bảo mật, còn email lại dễ bị phishing. TOTP chỉ thật sự có ý nghĩa khi dùng như một tiêu chuẩn mở, nhưng ngay cả vậy nó cũng không chặn được phishing hoàn toàn. Chỉ xác thực dựa trên phần cứng mới thực sự hiệu quả, nhưng lại có hạn chế là khó áp dụng thực tế ở các nền tảng quy mô lớn

    • Chuyện này không đơn giản đến mức chỉ cần "tuân thủ tốt tiêu chuẩn bảo mật là chặn được hết". Dù áp dụng biện pháp bảo mật hoàn hảo đến đâu, chỉ cần con người mắc sai lầm thì toàn bộ hệ thống vẫn dễ tổn thương. Không tồn tại hệ thống an toàn tuyệt đối. AI đang khiến email phishing trở nên khó phân biệt với thật, nhưng mặt khác cũng có thể dùng AI để phát hiện tốt hơn chính các cuộc tấn công này. Cuối cùng có lẽ vẫn phải dùng AI để phòng thủ

    • Trước đây phần lớn các vụ hack nhắm vào Windows, còn bây giờ số lượng nhà phát triển JavaScript và Python lớn hơn rất nhiều. Những cuộc tấn công như thế này về sau sẽ ngày càng tệ hơn

  • Tôi nghĩ NPM cũng có một phần trách nhiệm. Nhiều vendor bảo mật bên ngoài hay các startup có thể phát hiện hoạt động độc hại kiểu này rất nhanh, nên thật khó hiểu vì sao NPM, nơi có thể quan sát mọi package và sự kiện bảo mật theo thời gian thực, lại bất lực lặp đi lặp lại như vậy. Gần như ở mức cố tình làm ngơ

    • NPM giờ thuộc GitHub, tức là thuộc Microsoft. Có vẻ họ đang bận nhét AI tạo sinh như Copilot vào đủ loại ứng dụng

    • Tôi nghĩ với package có nhiều người quản lý, ít nhất nên có tùy chọn yêu cầu một quản trị viên khác phê duyệt thì mới được publish

    • Cùng một kẻ tấn công đã đưa payload bị làm rối mã (mà còn trông rất đáng ngờ) vào hơn 22 package đã không hoạt động trong thời gian dài rồi phát hành cùng lúc. Tôi nghĩ đòi NPM phải chặn được chuyện đó gần như là bất khả thi. Với tư cách người từng phát hành app/extension lên các nền tảng phần mềm khác, việc phải chờ vài ngày hay vài tuần là chuyện rất bình thường. Điều khiến tôi ngạc nhiên là dù MS và GitHub bán đủ loại giải pháp bảo mật, vẫn không thấy dấu hiệu họ đầu tư bài bản vào chính dịch vụ này

    • Tôi cũng không nghĩ NPM có lý do gì phải thay đổi. Nó đã là nguồn phát tán malware hơn 10 năm nay, nhưng chẳng ai ngừng dùng nên cũng không ảnh hưởng gì đến kinh doanh

    • Một phần nguyên nhân là package manager bị lạm dụng quá mức. Ngay từ đầu tôi đã không thích việc phụ thuộc vào cả những package nhỏ nhặt kiểu này. Tôi cũng rất ghét chuyện cứ kéo ngẫu nhiên phiên bản mới nhất về rồi làm hỏng môi trường. Không chỉ npm, mà package manager nói chung đều gây bực mình như nhau

  • Tôi nghĩ giờ mà còn tự nhập mật khẩu vào một website không khớp với domain chính thức, lại còn không dùng password manager, thì không đủ tư cách làm những việc quan trọng trên Internet

    • Password manager/tự động điền của trình duyệt hẳn đã cảnh báo về các domain giả mạo như vậy, và trong vụ phishing NPM lần này cũng đã chặn được sự không khớp giữa npmjs.help và domain chính thức

    • Điều đó đúng, nhưng trên thực tế tôi cũng đã nhiều lần gặp trường hợp ứng dụng chính thức và website chính thức dùng domain hoàn toàn khác nhau. Tệ nhất là khi app di động và web còn dùng domain khác hẳn nhau. Không hiểu ai lại thiết kế như vậy

  • Mỗi lần có sự cố kiểu này lặp lại, tôi lại không hiểu vì sao các package registry không bắt buộc mọi package phải được ký bằng mật mã. Tất nhiên nếu trong CI/CD việc ký được tự động hóa mà cả khâu đó cũng bị xâm phạm thì vẫn có thể bị vượt qua, nhưng ít nhất đa số vấn đề sẽ được ngăn chặn. Điều này đồng nghĩa nhà phát triển sẽ phải trải qua thêm các bước thủ công như tải artifact, ký và upload

    • Một registry đúng nghĩa thì giống Debian đã làm từ lâu rồi. npm quá nghiệp dư, nên trong môi trường doanh nghiệp lớn thường bị cấm dùng

    • Cách tôi thích là xác minh hậu kiểm. Sau khi CI/CD tự động upload xong, để việc phát hành thực sự chỉ xảy ra khi có người vào web bấm xác nhận thêm một lần. Như vậy vừa giảm ma sát trong quy trình release, vừa vẫn có bước con người phê duyệt lại

    • Nhưng vẫn còn bài toán khó là phải tin khóa ký nào. Bất kỳ ai chiếm được 2FA đều có thể đăng khóa mới để ký, nên có lẽ cần cách trì hoãn việc đăng ký khóa ký mới khi phát hiện hoạt động tài khoản đáng ngờ

  • Tôi đi đến kết luận là tránh npm registry sẽ có lợi hơn nhiều. Thay vào đó, tôi nghĩ lấy package trực tiếp từ (git) repository sẽ tốt hơn. npm registry vừa là con đường chính của các cuộc tấn công chuỗi cung ứng, vừa có vấn đề là mã nguồn và mã được phát hành bị tách rời hoàn toàn. npm publish có thể đưa thẳng bất kỳ đoạn mã cục bộ nào lên, nên kẻ xấu rất dễ chèn mã độc

    • Có vẻ khi phát hành lên npm từ GitHub builds thì có cơ chế xác minh tính xác thực, nhưng tôi vẫn chưa hiểu rõ vì dường như vẫn có thể publish từ môi trường khác

    • Với tư cách là một lập trình viên C, cảm giác rất kỳ lạ khi trước đây việc tối thiểu hóa dependency, dùng thư viện single-header, hay vendoring từng bị chê là lối cũ, còn bây giờ mọi người lại nhận ra đó là những cách làm cần thiết

    • Tính năng provenance gần đây của npm giải quyết đúng vấn đề này. Cấu hình cũng khá dễ, và nó sẽ giúp ngăn các kiểu tấn công như vậy. Tôi rất mừng khi thấy các package lớn đang lần lượt áp dụng

    • Không biết trong môi trường CI họ cũng dùng cách này không. Tôi muốn biết liệu có phải họ thay việc lấy package bằng npm install trên server bằng git clone hay không

    • Việc "lấy package trực tiếp từ git repository" nghe có vẻ hay trên lý thuyết, nhưng thực tế npm có rất nhiều bug, và cả những vấn đề ảnh hưởng đến cài đặt git dependency nữa. Như tôi đã viết trong issue này, do lỗi ở bước build nên đến tận năm 2020 nó vẫn không hoạt động đúng, và khi npm install toàn cục thì vẫn còn lỗi. Thậm chí dù script prepack được ghi rõ trong tài liệu npm, trên thực tế nó vẫn không chạy với dependency dựa trên git. Đội ngũ TypeScript compiler cũng buộc phải dùng cách vòng vèo kỳ quặc vì bug này, và còn để lại mã workaround cùng bug. Việc prepack thất bại mà không truyền exit code, khiến npm install kết thúc trong trạng thái hỏng mà không báo lỗi đúng cách, cũng là một vấn đề. Nhìn vào những chuyện này, tôi nghĩ npm rất cần được giám sát vận hành nghiêm túc hơn, hoặc bị thay thế hẳn bằng một package manager mới

  • Từ góc nhìn của người ngoài hệ sinh thái npm, tôi thật sự ngạc nhiên là vì sao họ lại kéo về nhiều package như vậy chỉ để làm những việc nhỏ nhặt đến thế

    • Lý do là standard library quá nghèo nàn, và ngay cả chức năng cơ bản cũng phải dùng package bên ngoài. Nếu tự làm thì ngay cả phần triển khai nhỏ nhặt cũng thành ra rất nhiều việc

    • Nói từ 15 năm kinh nghiệm phát triển, rất nhiều lập trình viên JavaScript làm công ăn lương thực ra gần như không biết lập trình. Đây không phải vấn đề năng lực trí tuệ, mà là do giáo dục và yếu tố văn hóa. Họ có nỗi sợ cực lớn với việc tự viết mã, nên cuối cùng cả những phần rất nhỏ cũng mặc định dựa vào dependency bên ngoài. Những người làm dự án sở thích thì ngược lại thường không như vậy, và code còn vững hơn nhiều. Nếu muốn kiểm chứng thì cứ bảo đồng nghiệp trong công ty tự build mà không dùng framework lớn là sẽ thấy ngay

    • Việc lấy các module nhỏ, đơn giản theo từng đơn vị là để tránh đưa cả đống mã không cần thiết vào phía client. Thư viện tổng hợp đúng là cho DX gọn gàng hơn, nhưng lại mang theo cả phần mã không mong muốn (dù có tree-shaking thì cũng không phải vạn năng)

    • Từ sau vụ leftpad, tranh cãi kiểu này vẫn tiếp diễn. Có thể là vì standard library của JS quá nhỏ

    • Với người review, một PR chỉ thêm một dòng import vào một module có vẻ "đáng tin" sẽ dễ chấp nhận hơn nhiều so với một thay đổi mã nguồn lớn. Thực tế không hẳn an toàn hơn, nhưng khi đang mệt thì nó dễ tạo cảm giác đáng tin hơn

  • Lần trước ở vụ nx tôi cũng nói điều tương tự: package manager nên có một "grace period" để luôn bỏ qua các package mới trong một khoảng thời gian nhất định, ví dụ 24 giờ. Phần lớn các cuộc tấn công kiểu này thường bị phát hiện và chặn rất nhanh ngay sau khi phát hành, nên nếu trong khoảng đó người dùng không tự động cài bản mới nhất thì có thể giảm đáng kể thiệt hại thực tế

  • Tôi có thể tưởng tượng được nỗi đau và căng thẳng mà tác giả đã trải qua. Chỉ vì một sai lầm duy nhất mà phải liên tục giải thích hẳn là rất khổ sở. Đây cũng là một ví dụ cho thấy hệ sinh thái mã nguồn mở đang phụ thuộc rất lớn vào những package thực chất do một người sở hữu. Chúng ta cần thừa nhận rằng ai cũng có thể bị hack chỉ vì một sai lầm. Xét về mặt kỹ thuật, trong bối cảnh AI được dùng nhiều như hiện nay, có lẽ deno/node/bun nên hiển thị cảnh báo với mã đáng ngờ, hoặc nên có kiểu phát hành @verified dựa trên xác thực như Debian để tăng độ tin cậy, cũng như chuyển văn hóa từ việc dùng bản mới nhất sang dùng bản đã được kiểm chứng. Tác giả cũng là con người và tất cả chúng ta nên đối xử tử tế. Khi vụ việc được xử lý xong, tôi cũng muốn xem thêm một bản phân tích kỹ thuật hoặc postmortem chi tiết hơn