React2Shell: Câu chuyện đằng sau lỗ hổng RCE nghiêm trọng trong React và Next.js
Một nhà nghiên cứu bảo mật đã tình cờ phát hiện lỗ hổng thực thi mã từ xa (RCE) mang tên React2Shell trong giao thức Flight của React. Lỗ hổng này khai thác cơ chế xử lý đối tượng phức tạp của React Server Components, ảnh hưởng đến hàng triệu ứng dụng Next.js và đã được Meta vá khẩn cấp.

React2Shell: Câu chuyện đằng sau lỗ hổng RCE nghiêm trọng trong React và Next.js
Vào ngày 30 tháng 11 năm 2025, nhà nghiên cứu bảo mật Lachlan Davidson đã báo cáo cho Meta về một lỗ hổng thực thi mã từ xa (RCE) nghiêm trọng được đặt tên là React2Shell. Chỉ ba ngày sau, Meta đã tung ra bản vá và công bố cảnh báo (CVE-2025-55182), kêu gọi các nhà phát triển cập nhật ngay lập tức.
Điều thú vị là Davidson không hề có ý định tìm kiếm lỗ hổng trong React ngay từ đầu. Anh chỉ muốn hiểu rõ một giao thức cụ thể để nâng cao kỹ năng tấn công vào các ứng dụng web hiện đại. Tuy nhiên, hành trình đó đã dẫn anh vào một "con thỏ" sâu thẳm, nơi ẩn chứa một lỗ hổng ảnh hưởng đến hàng triệu trang web.
Server Actions
Bối cảnh: Giao thức Flight và Server Actions
Trong những năm gần đây, Davidson đã kiểm thử xâm nhập (pentest) nhiều ứng dụng web được xây dựng trên Next.js - một khung công tác (framework) phổ biến dựa trên React. Next.js sử dụng React Server Components (RSC) để hiển thị nội dung hiệu quả trên máy chủ và React Server Functions (trước đây là Server Actions) để cho phép các tương tác của người dùng gọi mã JavaScript phía máy chủ một cách liền mạch.
Để hỗ trợ các tính năng này, trình duyệt và máy chủ cần một cách thức tinh tế để trao đổi thông điệp, vì các công nghệ hiện có không hoàn toàn phù hợp. Đội ngũ React đã phải xây dựng một cái mới có tên là Flight.
Bất kỳ ai từng kiểm thử ứng dụng web sử dụng Server Functions đều có thể quen thuộc với định dạng yêu cầu hơi kỳ lạ của Flight. Về cơ bản, nó trông giống như JSON nhưng có thêm các "chuông và còi" riêng. Tuy nhiên, cộng đồng bảo mật thường bỏ qua sự phức tạp này và chỉ test nó như một ứng dụng web truyền thống.
Một "Sự bỏ sót kiểm tra an toàn rõ ràng"
Flight cho phép truyền các đối tượng JavaScript phức tạp giữa client và server, bao gồm các loại dữ liệu mà JSON không thể đại diện được như Date, BigInt, Map, và cả các tham chiếu vòng (circular references).
Điểm mấu chốt nằm ở chỗ Flight cho phép tham chiếu đến các thuộc tính của một đối tượng. Vậy điều gì sẽ xảy ra nếu chúng ta cố gắng tham chiếu một thuộc tính không nằm trực tiếp trên đối tượng đó mà nằm trên nguyên mẫu (prototype) của nó?
Code Analysis
Kết quả là nếu gửi một thông điệp Flight tham chiếu đến một thuộc tính được kế thừa (ví dụ: Number.prototype.toString), server sẽ thành công truy xuất nó và đặt nó vào đối tượng do kẻ tấn công kiểm soát. Guillermo Rauch (tác giả gốc của Next.js) đã mô tả đây là "một sự bỏ sót kiểm tra an toàn rõ ràng".
Ảo giác về an toàn của TypeScript
Một vấn đề lớn khác là sự ảo giác an toàn mà TypeScript tạo ra. Hãy xem ví dụ về một React Server Function đơn giản:
async function sayHello(name: string): string {
'use server'
return 'Hello, ' + name + '!'
}
Đoạn mã này giả định một cách sai lầm rằng name là một chuỗi. Tuy nhiên, với Flight, kẻ tấn công có thể gửi một đối tượng tùy ý. Nếu đối tượng đó có một hàm được tham chiếu qua toString, khi server cố gắng nối chuỗi, nó sẽ ngầm gọi hàm đó.
Kiểu dữ liệu : string trong TypeScript chỉ mang tính kiểm tra lúc biên dịch (build-time), không được thực thi tại runtime (runtime). Đây là một con dao hai lưỡi khiến nhà phát triển lầm tưởng dữ liệu đầu vào an toàn.
Vũ khí hóa "Thenables" để đạt RCE
Để khai thác lỗ hổng này thành RCE, Davidson và cộng sự Sylvie Mayer đã tập trung vào việc lạm dụng cơ chế "thenables" trong JavaScript. Một "thenable" là bất kỳ đối tượng nào có phương thức .then, hoạt động tương tự như Promise.
Khi React giải mã một payload Flight, nó sử dụng await. Bên dưới, await sẽ gọi Promise.resolve, vốn rất "nhẹ nhàng" với các thenables. Bằng cách gửi một đối tượng tùy chỉnh có thuộc tính then trỏ đến một hàm dựng sẵn (như Array.prototype.push), kẻ tấn công có thể chuỗi các lời gọi hàm lại với nhau.
Exploit Chain
Quá trình khai thác cực kỳ phức tạp, liên quan đến việc thao túng các đối tượng nội bộ của React gọi là Chunk. Cuối cùng, Davidson đã tìm ra cách gọi Function("evilCode")(), cho phép thực thi mã JavaScript tùy ý trên máy chủ.
Công bố và khắc phục
Khi gửi báo cáo cho Meta, các bước tái hiện lỗ hổng đáng sợ đến mức đơn giản: cài đặt một ứng dụng Next.js/React mới, chạy script và RCE.
Đáng kinh ngạc là dù vào cuối tuần, đội ngũ Meta đã xác nhận báo cáo trong khoảng 17 giờ. Meta và đội ngũ React (bao gồm cả Vercel) đã làm việc không ngừng nghỉ để phát triển bản vá, phối hợp truyền thông và chuẩn bị CVE.
Lỗ hổng này, được đặt tên là React2Shell, nhắc nhở chúng ta rằng ngay cả những khung công tác được kiểm thử kỹ lưỡng nhất cũng có thể chứa những lỗ hổng sâu sắc trong các giao thức nội bộ của chúng. Các nhà phát triển sử dụng Next.js và React Server Actions được khuyến cáo mạnh mẽ cập nhật lên phiên bản mới nhất ngay lập tức.
Bài viết liên quan
Phần mềm
Lo ngại về Bun: Liệu sự suy giảm của Claude Code có phải là điềm báo cho tương lai của runtime này?
04 tháng 5, 2026

Phần mềm
Google phát hành Chrome 148, vá 127 lỗ hổng bảo mật bao gồm các lỗi nghiêm trọng
07 tháng 5, 2026

Phần mềm
Tấn công chuỗi cung ứng WordPress: Kẻ tấn công mua 30 plugin trên Flippa và cài cửa sau
06 tháng 5, 2026
