Bỏ qua tới nội dung
LẬP TRÌNHCẢNH BÁO

Lỗi Brotli trong Node.js: chỉ một lệnh fetch() cũng có thể thành cửa hậu

Node.js vừa vá 10 lỗi trên cả ba nhánh 22.x, 24.x, 26.x. Nặng nhất là lỗi ghi tràn bộ nhớ trong bộ giải nén Brotli, có thể bị kích hoạt chỉ qua fetch(). Đây là những gì bạn cần biết và phiên bản cần nâng lên.

BBeernary22/10/2026 · 14 PHÚT ĐỌC
COVER.BMP
Lỗi Brotli trong Node.js: chỉ một lệnh fetch() cũng có thể thành cửa hậu
▲ Node.js vá lỗi giải nén Brotli cùng 9 lỗ hổng khác trong đợt cập nhật tháng 10/2026

Bạn có một dịch vụ Node.js nhỏ chạy ổn định cả năm trời: nhận request, gọi fetch() sang một API bên ngoài, xử lý dữ liệu rồi trả kết quả. Bạn chưa từng viết dòng nào liên quan tới nén hay giải nén. Vậy mà sáng nay, nhóm chat kỹ thuật báo rằng chính đoạn code "vô hại" ấy có thể là cửa ngõ để kẻ xấu chạy mã trên máy chủ của bạn.

Ngày 21/10/2026, dự án Node.js phát hành bản cập nhật bảo mật vá 10 lỗi cùng lúc, trong đó nghiêm trọng nhất là lỗi trong bộ giải nén Brotli đi kèm Node.js. Bài này giải thích lỗi nằm ở đâu, vì sao ứng dụng của bạn có thể dính dù không hề gọi tới Brotli, mức độ nguy hiểm thực tế ra sao, và bạn cần nâng lên phiên bản nào.

Lập trình viên gõ code trên laptop đặt trên đùi

Đợt vá này gồm những gì và ai bị ảnh hưởng?

Bản cập nhật áp dụng cho cả ba nhánh Node.js còn được hỗ trợ. Mỗi nhánh có đúng một phiên bản đã vá:

Nhánh Loại Phiên bản an toàn
22.x LTS (hỗ trợ dài hạn) 22.23.4
24.x LTS (hỗ trợ dài hạn) 24.22.1
26.x Current (bản hiện hành) 26.12.1
20.x trở về trước Đã hết vòng đời Không có bản vá

Điểm cần chú ý nhất nằm ở dòng cuối: Node.js 20.x và các bản cũ hơn đã hết vòng đời (end of life) nên sẽ không nhận bản sửa. Nếu máy chủ của bạn vẫn chạy Node 18 hay Node 20, cách duy nhất là chuyển hẳn sang một nhánh còn được hỗ trợ.

Kiểm tra nhanh phiên bản đang chạy:

bash
node -v
Đừng chỉ kiểm tra máy của mình

Phiên bản Node trên laptop của bạn chưa chắc trùng với phiên bản trong Docker image, trên CI hay trên máy chủ production. Hãy kiểm tra ở mọi nơi ứng dụng thực sự chạy.

Brotli là gì mà nằm sẵn trong Node.js?

Brotli là thư viện nén dữ liệu do Google phát triển. Rất nhiều máy chủ web dùng Brotli để nén nội dung trước khi gửi đi cho nhẹ, giống như hút chân không túi quần áo để nhét vừa vali. Bên nhận phải "bơm phồng" lại, tức là giải nén, mới đọc được nội dung.

Node.js không dùng Brotli của hệ điều hành mà đóng gói sẵn một bản sao riêng bên trong. Đây là lý do lỗi này đáng chú ý: nó nằm trong code đi kèm Node.js, không nằm trong chương trình của bạn. Node.js chạy đoạn code đó mỗi khi giải nén dữ liệu Brotli, theo hai con đường:

  • Trực tiếp: code của bạn (hoặc một thư viện bạn dùng) gọi module node:zlib để giải nén.
  • Tự động: code gọi fetch() và máy chủ bên kia trả về phản hồi nén bằng Brotli. Node tự giải nén mà bạn không cần làm gì.

Con đường thứ hai chính là cái bẫy trong tình huống mở bài. Bạn không cần biết Brotli là gì, chỉ cần dùng fetch() là đã chạm tới bộ giải nén này.

Ứng dụng bị coi là có nguy cơ khi nó giải nén dữ liệu Brotli mà kẻ tấn công kiểm soát được, ví dụ:

  • Body của request gửi tới máy chủ của bạn.
  • Phản hồi lấy về từ một máy chủ khác, chẳng hạn khi bạn fetch() một URL do người dùng cung cấp hoặc một dịch vụ bên thứ ba bị chiếm quyền.

Lỗi "ghi tràn bộ nhớ" hoạt động thế nào?

Về kỹ thuật, đây là lỗi out-of-bounds write (ghi ra ngoài vùng nhớ cho phép) trong bộ giải mã Brotli, bị kích hoạt bởi dữ liệu nén bị làm sai định dạng một cách cố ý.

Hãy hình dung bạn chuẩn bị một chiếc vali vừa đúng cho số đồ đã khai báo. Nhưng chiếc túi chân không kẻ gian đưa cho bạn khi bơm phồng lại to hơn nhiều so với nhãn ghi. Bạn cứ nhét, và đồ tràn ra ngoài vali, đè lên cả đồ của người bên cạnh. Trong máy tính, "đồ của người bên cạnh" là những vùng nhớ chương trình đang dùng cho việc khác. Ghi đè đúng chỗ, kẻ tấn công có thể làm chương trình chạy theo ý mình.

Người phụ nữ cố đè nắp chiếc vali bị nhồi quá nhiều quần áo

Bản sửa là một bản vá từ chính dự án Brotli mà Node.js chép vào. Nó khiến bộ giải mã phát hiện dữ liệu không hợp lệ và dừng sớm hơn, thay vì cứ tiếp tục ghi vượt quá bộ đệm. Nói theo kiểu vali: kiểm tra túi trước khi mở, thấy sai là trả lại ngay.

Không chỉ Node.js

Cùng bản sửa này đã có trong Brotli 1.2.1, 1.1.1 và 1.0.10, phát hành ngày 21/10. Phần mềm nào khác cũng đóng gói sẵn Brotli có thể cần cập nhật tương tự. Một chi tiết thú vị: thay đổi này đã được đưa vào mã nguồn Brotli từ tháng 2/2026, nhưng tới tháng 10 mới được phát hành dưới dạng bản vá bảo mật.

"Thực thi mã từ xa" có đáng sợ như tên gọi?

Dự án Node.js mô tả lỗi này (CVE-2026-111497) là có thể dẫn tới Remote Code Execution (thực thi mã từ xa), tức kẻ tấn công có thể chạy mã tuỳ ý trên hệ thống bị ảnh hưởng. Tuy vậy, mức xếp hạng chính thức là High (cao), không phải Critical (nghiêm trọng). Và những gì đã được chứng minh trên thực tế hẹp hơn nhiều so với cái tên.

Kỹ sư bảo mật đeo tai nghe ngồi trước nhiều màn hình hiển thị mã và biểu đồ

Ngày 22/10, một proof-of-concept (mã khai thác mẫu) được công bố công khai. Kết quả của nó:

  • Trên bản build cố tình làm yếu đi để thử nghiệm: đạt được thực thi mã.
  • Trên bản build Node.js tiêu chuẩn: tác giả chỉ ghi nhận làm chương trình crash và đọc được một phần giới hạn bộ nhớ tiến trình, không thực thi được mã. Chính tác giả cho biết chưa tạo được cuộc tấn công hoạt động trên bản build thông thường.
  • Trên Node.js đã vá: dữ liệu sai định dạng mà mã mẫu sử dụng bị từ chối.
  • Tính tới ngày 22/10, chưa có báo cáo nào về việc lỗi bị khai thác ngoài thực tế.

Nói cách khác, cửa đã được chứng minh là có khe hở, nhưng chưa ai lách lọt người qua trên một ngôi nhà bình thường. Tuy nhiên, một lần crash cũng đủ làm dịch vụ gián đoạn, và việc đọc lén được bộ nhớ tiến trình không phải chuyện nhỏ. Mã khai thác mẫu đã công khai thì khoảng cách tới một cuộc tấn công thật chỉ còn là thời gian.

Chín lỗi còn lại đáng lo tới đâu?

Brotli chiếm hết tiêu đề, nhưng ba lỗi khác trong đợt này cũng xếp hạng High:

  • Vượt kiểm tra chứng chỉ TLS bằng địa chỉ IP viết kiểu lạ (CVE-2026-106069 và CVE-2026-105483): kẻ tấn công viết địa chỉ IP của máy chủ dưới dạng không chuẩn, khiến một chứng chỉ được chấp nhận cho máy chủ mà lẽ ra nó không được phép đại diện. Với riêng CVE-2026-105483, Node.js xếp hạng cao, dù commit sửa lỗi lại mô tả nó là mức thấp và khó khai thác.
  • dns.resolve cắt cụt tên miền (CVE-2026-105482): khi tên miền chứa ký tự null ở giữa, hàm này cắt tên tại đó, nghĩa là thứ được tra cứu không phải thứ bạn tưởng.

Thanh địa chỉ trình duyệt với biểu tượng ổ khoá xanh và giao thức https

Kiểm tra TLS giống như bảo vệ đối chiếu thẻ tên với khuôn mặt người vào cửa. Lỗi ở đây là bảo vệ bị lừa vì cùng một con số được viết theo kiểu chữ khác, như dùng chữ số "toàn chiều rộng" thay cho chữ số thường.

Trong nhóm mức trung bình, đáng chú ý nhất là CVE-2026-106074: khi ứng dụng được build dưới dạng startup snapshot hoặc single-executable application, hai hàm crypto.randomUUID() và crypto.randomInt() trả về cùng một giá trị ở mọi tiến trình. Bất cứ thứ gì dựa vào tính khó đoán của các giá trị này đều mất tác dụng.

Toàn bộ 10 lỗi:

CVE Lỗi là gì Mức độ Nhánh bị ảnh hưởng
CVE-2026-111497 Ghi tràn bộ nhớ trong bộ giải mã Brotli, có thể thực thi mã từ xa theo dự án Cao 22.x, 24.x, 26.x
CVE-2026-106069 Vượt kiểm tra tên máy chủ TLS khi máy chủ phân giải ra IP dạng không chuẩn Cao 22.x, 24.x, 26.x
CVE-2026-105483 Vượt kiểm tra tên máy chủ TLS khi IP viết bằng chữ số toàn chiều rộng Cao 24.x, 26.x
CVE-2026-105482 dns.resolve cắt cụt tên chứa ký tự null Cao 22.x, 24.x, 26.x
CVE-2026-105481 Socket keep-alive có thể xử lý phản hồi được ghi trước khi request được gửi Trung bình 22.x, 24.x, 26.x
CVE-2026-106072 Kiểm tra chứng chỉ cho IPv4 dạng không chuẩn cho phép tên miền xác thực điểm cuối IP Trung bình 22.x, 24.x, 26.x
CVE-2026-106074 Bộ đệm của randomUUID() và randomInt() bị dùng lại trong snapshot và ứng dụng đơn tệp Trung bình 22.x, 24.x, 26.x
CVE-2026-106070 ZipFile trả về dữ liệu do kẻ tấn công kiểm soát sau khi kiểm tra header thất bại Thấp 26.x
CVE-2026-106071 Permission Model cấp quyền truy cập tệp quá rộng qua tra cứu wildcard Thấp 26.x
CVE-2026-106073 Vượt Permission Model bằng fs.realpathSync Thấp 22.x, 24.x, 26.x

Vì sao Node.js "cấm cửa" chứng chỉ của eMudhra?

Ngoài 10 lỗi trên, bản cập nhật còn khiến Node.js ngừng tin tưởng 8 khoá của cơ quan cấp chứng chỉ trung gian thuộc nhà cung cấp Ấn Độ eMudhra, vốn được báo cáo là đã bị lộ vài ngày trước đó.

Ba biểu tượng ổ khoá xanh, vàng, đỏ thể hiện trạng thái kết nối an toàn và không an toàn

Vấn đề nằm ở cách Node.js xác minh chứng chỉ. Node dùng danh sách chứng chỉ gốc của Mozilla nhưng mặc định không kiểm tra thu hồi (revocation). Hãy hình dung một con dấu bị đánh cắp: nếu nơi nhận giấy tờ không bao giờ tra danh sách "dấu đã mất", giấy tờ đóng bằng con dấu đó vẫn được chấp nhận. Vì vậy trước bản cập nhật, một chuỗi chứng chỉ dựng trên một trong các khoá bị lộ vẫn được Node coi là hợp lệ.

Bản cập nhật xử lý theo hai hướng:

  • Chặn cứng 8 khoá ngay trong Node.js.
  • Cập nhật danh sách chứng chỉ gốc đi kèm, gỡ bỏ ba chứng chỉ gốc emSign.

Ngôn ngữ Go cũng đã chặn tương tự trong bản cập nhật ngày 20/10.

Hai lỗ hổng còn sót

Các kết nối được nối lại (resume) từ một phiên bắt đầu trước khi cập nhật sẽ không bị kiểm tra lại cho tới khi phiên đó hết hạn. Và các nhánh đã hết vòng đời không nhận được lệnh chặn này.

Còn những thành phần nào được làm mới?

Node.js không chỉ là code của riêng nó mà còn đóng gói nhiều thư viện bên trong. Đợt này, các thành phần sau cũng được cập nhật:

  • undici, thư viện HTTP đứng sau fetch(): lên phiên bản sửa 3 lỗi mức trung bình, gồm một lỗi trong cơ chế kiểm tra Subresource Integrity và hai lỗi cạn kiệt bộ nhớ, trong đó một lỗi nằm ở WebSocket client tích hợp sẵn trong Node.js.
  • c-ares (thư viện phân giải DNS): cập nhật trên mọi nhánh.
  • OpenSSL: cập nhật trên nhánh 22.x và 24.x.
  • SQLite: cập nhật trên nhánh 22.x.

Các bản cập nhật thư viện này nhằm đưa vào bản sửa cho những lỗ hổng đã được công bố công khai.

Trình soạn thảo code đang tạm dừng ở breakpoint khi debug một ứng dụng Node.js

Chưa nâng cấp ngay được thì làm gì?

Câu trả lời ngắn và hơi phũ: nâng cấp chính là bản sửa. Thông báo của dự án không đưa ra cách khắc phục tạm thời nào cho lỗi Brotli, nghĩa là bên trong Node.js không có công tắc nào để tắt tạm cho an toàn.

Một ví dụ về giảm thiểu từ phía hạ tầng: Vercel, nền tảng chạy Node.js cho khách hàng, cho biết đã thêm luật tường lửa từ ngày 21/10 để chặn kiểu tấn công này trong các request gửi tới. Nhưng chính Vercel nói rõ hai giới hạn:

  • Luật này không bảo vệ các phản hồi Brotli mà ứng dụng tự fetch() về từ máy chủ khác.
  • Nó không thay thế việc nâng cấp.

Sơ đồ tường lửa ngăn giữa mạng nội bộ LAN và mạng bên ngoài WAN

Tường lửa giống như bảo vệ đứng ở cổng trước: soát được người đi vào, nhưng không soát được những gói hàng bạn tự đặt ship về nhà. Mà con đường fetch() lại chính là "gói hàng tự đặt".

Danh sách việc cần làm:

  • [ ]Chạy node -v ở mọi môi trường: máy dev, CI, Docker image, production
  • [ ]Nâng nhánh 22.x lên 22.23.4, 24.x lên 24.22.1, 26.x lên 26.12.1
  • [ ]Còn Node 20 trở xuống thì lên kế hoạch chuyển sang nhánh còn hỗ trợ
  • [ ]Rà soát chỗ nào ứng dụng fetch() URL do người dùng cung cấp hoặc giải nén body request
  • [ ]Nếu ứng dụng có đóng gói Brotli riêng ngoài Node.js, kiểm tra bản cập nhật Brotli 1.2.1, 1.1.1 hoặc 1.0.10
  • [ ]Nếu build ứng dụng dạng snapshot hoặc single-executable, build lại sau khi nâng cấp

Không có đường tắt cho đợt này: nâng phiên bản Node.js là cách duy nhất để vá lỗi Brotli.

Tóm tắt nhanh

  • Ngày 21/10/2026, Node.js vá 10 lỗi trên ba nhánh 22.x, 24.x, 26.x. Phiên bản an toàn: 22.23.4, 24.22.1, 26.12.1. Node 20.x trở xuống không được vá.
  • Lỗi nặng nhất là ghi tràn bộ nhớ trong bộ giải mã Brotli đi kèm Node, có thể bị kích hoạt chỉ qua fetch() một phản hồi nén Brotli.
  • Dự án gọi đây là lỗi có thể thực thi mã từ xa, xếp hạng High. Mã khai thác mẫu trên bản build chuẩn mới chỉ gây crash và đọc được một phần bộ nhớ; chưa có khai thác ngoài thực tế tính tới 22/10.
  • Bản cập nhật còn chặn 8 khoá chứng chỉ trung gian bị lộ của eMudhra và làm mới undici, c-ares, OpenSSL, SQLite.
  • Không có cách khắc phục tạm thời; tường lửa chỉ chặn được một chiều. Hãy nâng cấp.

Câu hỏi thường gặp

Ứng dụng của tôi không dùng zlib, có bị ảnh hưởng không?

Có thể có. Chỉ cần ứng dụng gọi fetch() và máy chủ bên kia trả về phản hồi nén Brotli, Node.js sẽ tự giải nén bằng đúng đoạn code bị lỗi. Nguy cơ thực sự xuất hiện khi dữ liệu Brotli đó do kẻ tấn công kiểm soát.

Lỗi Brotli đã bị khai thác ngoài thực tế chưa?

Tính tới ngày 22/10/2026, chưa có báo cáo nào. Mã khai thác mẫu công khai chỉ đạt thực thi mã trên một bản build cố tình làm yếu; trên bản build chuẩn, nó gây crash và đọc được một phần giới hạn bộ nhớ.

Tôi đang dùng Node.js 20, chờ bản vá được không?

Không. Node.js 20.x và các bản cũ hơn đã hết vòng đời, sẽ không nhận bản sửa lỗi Brotli lẫn lệnh chặn chứng chỉ eMudhra. Bạn cần chuyển sang nhánh 22.x, 24.x hoặc 26.x.

Dùng tường lửa như Vercel là đủ chưa?

Chưa. Luật tường lửa của Vercel chặn tấn công trong request gửi tới, nhưng không bảo vệ phản hồi Brotli mà ứng dụng tự lấy về từ máy chủ khác, và chính Vercel nói nó không thay thế việc nâng cấp.

BVIẾT BỞIBeernary

ĐỌC TIẾP_

BÌNH LUẬN (0)

LOGIN.EXE
> ĐĂNG NHẬP ĐỂ BÌNH LUẬNDùng tài khoản Google, không cần tạo mật khẩu. Tên và ảnh đại diện Google sẽ hiện cạnh bình luận.

> CHƯA CÓ BÌNH LUẬN. HÃY LÀ NGƯỜI ĐẦU TIÊN_