Quay lại

2026/10/28

Node2Shell (CVE-2026-111497): hệ thống nào có nguy cơ và cần làm gì ngay

CVE-2026-111497 trong Brotli thực sự ảnh hưởng hệ thống nào, mức khẩn cấp của từng trường hợp và các bước vá, build lại, khởi động lại, giảm thiểu.

Cập nhật ngày 27 tháng 10 năm 2026

CVE-2026-111497, còn được gọi là “Node2Shell” hay “HTTP2Shell”, là lỗi hỏng bộ nhớ (memory corruption) trong bộ giải nén Brotli. Brotli là định dạng nén br được dùng rộng rãi trên web. Lỗi nằm trong thư viện Brotli của Google, từ phiên bản 1.0.3 đến 1.2.0 [1]. Node.js tích hợp sẵn thư viện này, và dự án Node.js đánh giá vấn đề ở mức High (Cao) cho các dòng 22.x, 24.x và 26.x [2]. Cùng bộ giải mã này cũng có mặt trong các gói Python, thư viện hệ thống Linux, ứng dụng desktop và công cụ dành cho lập trình viên, vì vậy phạm vi ảnh hưởng thực tế rộng hơn nhiều so với “các máy chủ Node.js”.

Bài viết này dành cho các nhóm cần nhanh chóng xác định mình có bị ảnh hưởng hay không và cần làm gì trước tiên.

Tóm lại: Nếu bất kỳ hệ thống nào của bạn giải nén dữ liệu Brotli đến từ một bên mà bạn không kiểm soát (một client trên internet, một website bên ngoài, một bên gửi webhook, một tệp được tải lên), hãy coi đây là việc khẩn cấp. Hãy vá lỗi, build lại, khởi động lại, và trong thời gian chờ hãy chặn br.

Lỗ hổng gây ra điều gì

Bộ giải mã xử lý sai một “block switch” bị lỗi định dạng trong luồng dữ liệu nén. Nó coi lỗi này là “cần thêm dữ liệu đầu vào” thay vì “dữ liệu này không hợp lệ”, và liên tục ghi thêm byte vào một bộ đệm nội bộ nhỏ có kích thước cố định cho đến khi ghi tràn qua phần cuối của bộ đệm [2]. Kẻ tấn công nào khiến được ứng dụng của bạn giải nén một luồng Brotli được tạo có chủ đích đều có thể làm hỏng bộ nhớ của tiến trình. Điều đó có thể dẫn đến:

  • Sập tiến trình (từ chối dịch vụ). Đây là kết quả kẻ tấn công đạt được ổn định nhất.
  • Rò rỉ bộ nhớ tiến trình. Phản hồi hoặc log có thể làm lộ một phần secret, token hoặc dữ liệu của người dùng khác.
  • Có thể dẫn đến thực thi mã từ xa. Node.js liệt kê RCE là một tác động có thể xảy ra [2]. Bản proof of concept công khai đầu tiên chỉ đạt được thực thi mã trên một bản build đã bị cố ý làm suy yếu, nhưng sau đó các nhà nghiên cứu đã báo cáo thực thi được mã, dù chưa ổn định, trên bản build Node.js 24.22.0 chính thức, không bị chỉnh sửa [3].

Không cần xác thực: kẻ tấn công chỉ cần đưa được các byte đến bộ giải mã. Đó là lý do điểm CVSS 4.0 là 9.2 (mức Critical) [1]. Vì vậy, câu hỏi then chốt với mọi hệ thống không phải là “chúng ta có dùng Brotli không?” mà là “một bên không đáng tin cậy có thể khiến chúng ta giải nén Brotli hay không?”

Các trường hợp sử dụng điển hình và mức độ rủi ro

Trường hợp 1: API công khai trên internet chấp nhận body request được nén (ưu tiên cao nhất)

Một số máy chủ API Node.js, BFF, API gateway và endpoint tải lên giải nén body request được gửi kèm Content-Encoding: br. Số khác làm điều tương tự thông qua middleware. Rủi ro: bất kỳ client ẩn danh nào trên internet cũng có thể gửi một body được tạo có chủ đích. Hậu quả có thể từ việc làm sập dịch vụ liên tục, tức một cuộc tấn công DoS chi phí thấp, cho đến rò rỉ bộ nhớ từ tiến trình đang giữ dữ liệu phiên và API key. Mức độ khẩn cấp: khẩn cấp. Hãy vá ngay hôm nay và chặn body request br tại lớp biên (edge) cho đến khi vá xong.

Trường hợp 2: Dịch vụ lấy nội dung từ bên ngoài (ưu tiên cao)

Các dịch vụ nhận webhook, crawler và scraper, dịch vụ xem trước liên kết và RSS, tích hợp thanh toán hoặc SaaS, và các AI agent duyệt web đều thực hiện request HTTP ra bên ngoài. Nhiều HTTP client gửi Accept-Encoding: br và tự động giải nén phản hồi. Trong Python, urllib3 và requests làm điều này bất cứ khi nào gói Brotli hoặc brotlicffi được cài đặt, kể cả khi mã của bạn không hề import gói đó. aiohttp cũng vậy, còn httpx làm vậy khi được cài kèm tùy chọn mở rộng brotli [4]. Rủi ro: một máy chủ từ xa độc hại, bị xâm nhập hoặc giả mạo có thể tấn công backend của bạn thông qua phản hồi của nó. Kẻ tấn công hoàn toàn không cần tiếp cận mạng của bạn: chính bạn gọi đến họ. Mức độ khẩn cấp: cao. Hãy vá trước ở những nơi có đích đến không hoàn toàn đáng tin cậy.

Trường hợp 3: Ứng dụng desktop, AI coding agent và CLI có runtime nhúng

Ứng dụng Electron, CLI dựa trên Bun hoặc Node và các công cụ AI cho lập trình viên mang theo bản sao runtime riêng. Cập nhật gói node của hệ thống không khắc phục được chúng. Cập nhật ứng dụng trên đĩa cũng không khắc phục được các bản đang chạy: các tiến trình chạy lâu dài vẫn giữ runtime cũ trong bộ nhớ cho đến khi được khởi động lại. Rủi ro: các công cụ này thường nắm giữ thông tin xác thực và lấy nội dung từ bên ngoài, tức là kết hợp Trường hợp 2 với một tiến trình có đặc quyền. Mức độ khẩn cấp: cao đối với các công cụ lấy nội dung không đáng tin cậy. Hãy cập nhật chúng, rồi thực sự khởi động lại. Chúng tôi đã phân tích chi tiết cái bẫy “đã cập nhật nhưng vẫn chạy mã cũ” trong bài HTTP2Shell: vì sao cập nhật binary không khắc phục được các tiến trình đang chạy.

Trường hợp 4: Container image và artifact CI/CD

Các image được build FROM node:22, node:24 hoặc node:26 trước khi có bản sửa vẫn chứa runtime có lỗ hổng, ngay cả khi máy host đã được vá. Điều tương tự cũng áp dụng cho các Python wheel được đóng gói kèm và các dependency được vendor. Rủi ro: mã có lỗ hổng sẽ quay trở lại sau mỗi lần deploy và mỗi sự kiện autoscaling cho đến khi image được build lại. Mức độ khẩn cấp: cao đối với các image phục vụ Trường hợp 1 và 2. Hãy build lại thay vì chỉ khởi động lại.

Trường hợp 5: Thư viện hệ thống Linux, font chữ và xử lý ảnh

Các bản phân phối cung cấp bộ giải mã dưới dạng thư viện dùng chung, ví dụ libbrotli1 trên Ubuntu/Debian. Thư viện này được curl và libcurl sử dụng khi bật nén, được FreeType dùng cho web font WOFF2, và được dùng gián tiếp bởi các công cụ xử lý ảnh và tài liệu như Pillow. Rủi ro: các hệ thống render font hoặc tài liệu do người dùng tải lên, hoặc lấy nội dung bên ngoài bằng curl --compressed, có thể bị dữ liệu Brotli không đáng tin cậy tiếp cận. Một máy chủ không bao giờ đưa dữ liệu bên ngoài vào các thư viện này có mức độ phơi nhiễm thực tế thấp. Mức độ khẩn cấp: trung bình trong đa số trường hợp, nhưng cao đối với các dịch vụ render tài liệu hoặc xử lý tệp tải lên. Ubuntu đã phát hành các gói brotli đã sửa lỗi cho 22.04, 24.04, 26.04 và 26.10 [1]. Với RHEL, Oracle Linux và các bản phân phối khác, hãy kiểm tra thông báo bảo mật của nhà cung cấp cho gói brotli thay vì tự giả định trạng thái.

Trường hợp 6: Hệ thống chỉ dùng nội bộ với đầu vào đáng tin cậy (ưu tiên thấp hơn)

Một số dịch vụ chỉ giải nén Brotli từ dữ liệu do chính bạn tạo ra, chẳng hạn cache nội bộ hoặc artifact build của chính bạn. Các hệ thống này có rủi ro thấp hơn, nhưng không phải bằng không: kẻ tấn công đã có chỗ đứng trong hệ thống có thể lợi dụng lỗi này để tiến sâu hơn. Mức độ khẩn cấp: vá trong chu kỳ cập nhật định kỳ tiếp theo.

Cần làm gì: các bước ứng phó

Bước 1: Xác định nơi Brotli được giải mã (ngay hôm nay)

  • Node.js: kiểm tra node -v trên mọi máy chủ, cũng như trong mọi container image và CI runner. Tìm trong mã nguồn và cấu hình các lệnh brotliDecompress, createBrotliDecompress và middleware phân tích body có giải nén br.
  • Runtime nhúng: liệt kê các ứng dụng Electron, CLI Bun/Node và AI agent đang được sử dụng, và ghi lại phiên bản runtime mà mỗi ứng dụng nhúng, chứ không chỉ phiên bản ứng dụng.
  • Python: chạy pip show Brotli brotlicffi trong từng môi trường và image. Tìm httpx[brotli] và các dependency bắc cầu (transitive) trong lockfile và SBOM.
  • Gói hệ điều hành: dpkg -l | grep brotli hoặc rpm -qa | grep brotli, sau đó xem những tiến trình nào thực sự nạp thư viện này.
  • Sắp xếp ưu tiên theo các trường hợp ở trên: mọi thứ có thể bị đầu vào không đáng tin cậy tiếp cận (Trường hợp 1, 2, 3 và 5 có xử lý tệp tải lên) cần được xử lý trước.

Bước 2: Vá các thành phần bị ảnh hưởng

  • Node.js: nâng cấp lên 22.23.4, 24.22.1 hoặc 26.12.1 hoặc mới hơn [2].
  • Python: Brotli>=1.2.1 hoặc brotlicffi>=1.2.1.0. Tạo lại lockfile [4].
  • Brotli upstream / mã C được vendor: 1.0.10, 1.1.1 hoặc 1.2.1, tùy theo nhánh [1].
  • Gói hệ điều hành: áp dụng bản cập nhật bảo mật của bản phân phối bạn dùng cho brotli / libbrotli.
  • Ứng dụng desktop và agent: cập nhật lên các bản phát hành mà nhà cung cấp xác nhận đã bao gồm runtime đã sửa lỗi. Nếu nhà cung cấp chưa công bố gì, hãy coi ứng dụng là chưa được xác minh, chứ không phải an toàn.

Bước 3: Build lại, triển khai lại và khởi động lại

  • Build lại container image từ base image đã được vá và triển khai lại. Khởi động lại một image cũ không giúp ích gì.
  • Khởi động lại mọi tiến trình chạy lâu dài đã nạp thư viện có lỗ hổng: các dịch vụ Node, worker, phiên agent và bất cứ thứ gì liên kết với thư viện hệ thống. Với các job có trạng thái và AI agent, hãy drain hoặc chuyển giao công việc trước để không làm mất các sự kiện đang xếp hàng hoặc các yêu cầu phê duyệt.

Bước 4: Giảm thiểu rủi ro trong khi vá

  • Chiều vào: từ chối các body request có Content-Encoding chứa br tại reverse proxy, load balancer hoặc WAF, trước khi bất kỳ bộ giải mã nào tiếp nhận chúng.
  • Chiều ra: chỉ loại bỏ br khỏi Accept-Encoding là chưa đủ, vì máy chủ độc hại vẫn có thể gửi br. Hãy đồng thời từ chối hoặc không giải mã các phản hồi đến kèm Content-Encoding: br [4].
  • Phương án dự phòng cho Python: ở những nơi chưa thể nâng cấp ngay, hãy gỡ cài đặt Brotli và brotlicffi để các client ngừng giải mã br. Hãy kiểm thử trước, vì một số máy chủ vẫn sẽ gửi br.

Bước 5: Xác minh và theo dõi dấu hiệu khai thác

  • Xác nhận phiên bản runtime từ bên trong tiến trình hoặc container đang chạy, không chỉ từ trình quản lý gói.
  • Quét lại image và SBOM để chắc chắn không còn bản sao cũ nào vẫn bị kéo vào theo kiểu bắc cầu.
  • Xem lại log gần đây để tìm các sự cố sập không rõ nguyên nhân, lỗi segmentation fault hoặc vòng lặp khởi động lại ở các dịch vụ xử lý br. Một loạt sự cố sập từ cùng một nguồn đáng được điều tra như một nỗ lực tấn công.
  • Nếu một dịch vụ có mức phơi nhiễm cao bị sập bất ngờ trước khi được vá, hãy cân nhắc thay mới (rotate) các secret mà tiến trình đó nắm giữ, vì không thể loại trừ khả năng bộ nhớ đã bị lộ.

Tóm tắt

Tình huốngRủi roHành động
API công khai giải mã body request brNghiêm trọngVá ngay; chặn br tại lớp biên
Backend lấy URL, webhook hoặc trang web bên ngoàiCaoVá ngay; từ chối phản hồi br
Ứng dụng Electron, AI agent hoặc CLI có runtime nhúngCaoCập nhật và khởi động lại mọi phiên bản đang chạy
Container image và artifact CI cũCaoBuild lại từ base image đã vá và triển khai lại
Thư viện hệ thống dùng cho tệp tải lên, font hoặc curl --compressedTrung bình–CaoÁp dụng bản cập nhật hệ điều hành; khởi động lại các dịch vụ nạp thư viện này
Chỉ dữ liệu nội bộ, đáng tin cậyThấp–Trung bìnhVá trong chu kỳ tiếp theo

Vá gói mới chỉ là một nửa công việc. Nguy cơ chỉ thực sự được loại bỏ khi không còn tiến trình đang chạy, image hay runtime nhúng nào vẫn có thể giải mã dữ liệu Brotli không đáng tin cậy bằng mã cũ.

Tài liệu tham khảo