Báo cáo sự cố tấn công chuỗi cung ứng chính thức từ đội ngũ bảo mật PyPI: vụ gói độc hại LiteLLM·Telnyx và cách phòng vệ
(blog.pypi.org)🔑 Tóm tắt chính
Thông qua lỗ hổng trong phụ thuộc của Trivy, token API đã bị đánh cắp, từ đó các phiên bản độc hại của gói litellm và telnyx được phát tán lên PyPI. Mã độc được thực thi ngay khi cài đặt, thu thập thông tin xác thực và tệp nhạy cảm rồi rò rỉ chúng tới máy chủ bên ngoài.
⚠️ Vì sao mã độc lần này đặc biệt
Phần lớn các gói độc hại trên PyPI trước đây là gói mới được tạo ra (như typosquatting). Đợt tấn công lần này khác hẳn. Nó sử dụng cách chèn mã độc vào các gói mã nguồn mở vốn đã được dùng rộng rãi.
Có hai đường chèn chính:
- Tấn công trực tiếp vào các dự án mã nguồn mở có kho lưu trữ, quy trình phát hành hoặc cơ chế xác thực yếu
- Đánh cắp token API và khóa trên máy của nhà phát triển đang cài phiên bản mới nhất
Đây là cấu trúc tấn công dây chuyền, dùng token API của PyPI hoặc GitHub đã bị đánh cắp để tiếp tục xâm phạm thêm các gói mã nguồn mở khác.
📅 Dòng thời gian sự cố
LiteLLM
Đã có hơn 119.000 lượt tải xuống trong thời gian phiên bản độc hại bị lộ diện.
PyPI đã nhận 13 báo cáo thông qua tính năng "báo cáo mã độc".
| Giai đoạn | Thời gian |
|---|---|
| Tải lên → báo cáo đầu tiên | 1 giờ 19 phút |
| Báo cáo đầu tiên → cách ly | 1 giờ 12 phút |
| Tổng thời gian bị lộ | 2 giờ 32 phút |
LiteLLM được cài khoảng 15~20 triệu lần mỗi tuần, tương đương khoảng 1.700 lượt/phút. Trong số này, khoảng 40~50% không ghim phiên bản, nên tự động nhận phiên bản mới nhất.
Telnyx
Gói telnyx đã được cách ly tự động nhờ trusted reporters pool của PyPI.
| Giai đoạn | Thời gian |
|---|---|
| Tải lên → báo cáo đầu tiên | 1 giờ 45 phút |
| Báo cáo đầu tiên → cách ly | 1 giờ 57 phút |
| Tổng thời gian bị lộ | 3 giờ 42 phút |
🛡️ Khuyến nghị bảo mật cho nhà phát triển
1. Cooldown cho phụ thuộc (Dependency Cooldowns)
Đây là chiến lược cấu hình để không cài các gói mới phát hành trong một khoảng thời gian nhất định, giúp các nhà nghiên cứu bảo mật và quản trị viên PyPI có thêm thời gian phản ứng.
uv — hiện đã hỗ trợ:
# ~/.config/uv/uv.toml hoặc pyproject.toml
[tool.uv]
exclude-newer = "P3D" # loại trừ các gói được phát hành trong vòng 3 ngày
pip v26.1 — dự kiến hỗ trợ trong tháng 4:
# ~/.config/pip/pip.conf
[install]
uploaded-prior-to = P3D
> ⚠️ Cooldown không phải là giải pháp vạn năng. Khi cần bản vá bảo mật, bạn vẫn phải cài ngay, vì vậy nên dùng song song với các công cụ quét lỗ hổng như Dependabot hoặc Renovate.
2. Khóa phụ thuộc (Lock Files)
pip freeze chỉ ghi lại phiên bản, không phải lock file. Để đảm bảo an toàn, bạn cần lock file thực sự có checksum/hash đi kèm.
Công cụ được khuyến nghị:
uv lockpip-compile --generate-hashespipenv
🔒 Khuyến nghị bảo mật cho maintainer mã nguồn mở
1. Tăng cường bảo mật quy trình phát hành
- Không dùng trigger không an toàn —
pull_request_targetcủa GitHub Actions đặc biệt rủi ro - Vô hại hóa tham số và giá trị đầu vào — truyền qua biến môi trường để ngăn template injection
- Không dùng tham chiếu có thể thay đổi — dùng commit SHA thay cho Git tag, và duy trì lock file cho phụ thuộc
- Thiết lập phát hành cần xét duyệt — kết hợp Trusted Publishers + GitHub Environments để yêu cầu phê duyệt bổ sung khi phát hành
Nếu đang dùng GitHub Actions, bạn nên kiểm tra lỗ hổng workflow bằng công cụ Zizmor.
2. Dùng Trusted Publishers thay cho API token
- API token có thời hạn hiệu lực dài, nên khi bị đánh cắp rất khó phát hiện ngay
- Trusted Publishers dùng token ngắn hạn, nên ngay cả khi bị lộ thì kẻ tấn công cũng phải dùng ngay, làm giảm rủi ro
- Thông qua Digital Attestations, người dùng downstream có thể phát hiện các bản phát hành không đi qua workflow phát hành hợp lệ
3. Bắt buộc 2FA
Từ năm 2024, PyPI đã bắt buộc 2FA khi phát hành gói. Tuy nhiên, không chỉ tài khoản PyPI, mà mọi tài khoản liên quan đến phát triển mã nguồn mở như GitHub, GitLab, email... đều phải bật 2FA (tốt nhất là khóa phần cứng).
💰 Nếu muốn hỗ trợ hoạt động này
Các hoạt động bảo mật của PyPI được duy trì nhờ sự hỗ trợ từ Python Software Foundation (PSF). Bạn có thể tham gia chương trình tài trợ của PSF, quyên góp trực tiếp, hoặc liên hệ sponsors@python.org.
> Vị trí kỹ sư bảo mật PyPI của Mike Fiedler và Seth Larson đang nhận tài trợ từ Alpha-Omega.
1 bình luận
Tôi đã thử tạo một máy chủ MCP rồi đưa lên npm, và đọc báo cáo vụ việc này thấy khá rùng mình.
Cuối cùng thì các máy chủ MCP cũng được đưa nguyên trạng lên npm, PyPI, mà cũng có khá nhiều trường hợp cài đặt mà không khóa phiên bản; các thứ như cơ chế báo cáo hay trusted publisher thì vẫn chưa có. Dù LiteLLM chỉ bị lộ hơn 2 tiếng một chút mà số lượt tải đã như vậy, nên tôi có cảm giác bên này một khi đã lọt vào thì sẽ còn tồn tại khá lâu.
Bên Claude Code tôi cũng thấy có trường hợp các thiết lập bảo vệ kiểu này không được áp dụng đúng khi
pip install, nên nếu theo luồng mà agent tự cài package thì khá mơ hồ là nên chặn ở đâu.