TL;DR

CVE-2026-41242 (GHSA-xq3m-2v4x-88gg) là lỗ hổng Remote Code Execution critical trong protobuf.js — JavaScript runtime phổ biến nhất cho Protocol Buffers, với khoảng 52 triệu lượt tải mỗi tuần trên npm. Điểm CVSS 4.0 là 9.4. Kẻ tấn công chỉ cần tuồn một schema .proto độc hại vào ứng dụng; khi app decode message đầu tiên của type đó, code tuỳ ý chạy trong process Node.js — không cần xác thực, không cần user tương tác. Fix: nâng lên protobufjs@^8.0.1 hoặc ^7.5.5 ngay.

What's new

Ngày 18/04/2026, Endor Labs công bố báo cáo chi tiết về một lỗ hổng do researcher Cristian Staicu phát hiện và báo cho maintainer protobuf.js từ 02/03/2026. Patch đã nằm trong repo từ 11/03, nhưng bản npm mới được phát hành đầy đủ: 8.0.1 ngày 04/04 và 7.5.5 ngày 15/04. Advisory chính thức (GHSA-xq3m-2v4x-88gg) được publish 16/04, CVE-2026-41242 được NVD ghi nhận 18/04.

Đây không phải bug logic khó hiểu — đây là code injection nguyên chất: định danh type trong schema được nối thẳng vào chuỗi JavaScript và truyền cho Function() constructor. Trong suốt nhiều năm, hai call site dùng Function(...) đều bị gắn comment // eslint-disable-line no-new-func, và không ai lần ngược dòng dữ liệu đi vào đó.

Why it matters

protobuf.js không phải lib ngoại biên. Nó là xương sống JS runtime cho Protocol Buffers — định dạng serialization mặc định của gRPC, Firebase, Google Cloud SDKs, service mesh (Envoy xDS), và cả tỉ pipeline telemetry/observability. Nếu node_modules của bạn có bất cứ thứ gì "cloud-adjacent", gần như chắc chắn có protobufjs — thường là dependency gián tiếp qua @grpc/proto-loader, Firebase SDK, hoặc Google Cloud client.

Điểm nguy hiểm: payload kích hoạt ở runtime, trên đường decode — không phải build time. Request bình thường từ user hoặc partner đi vào là đủ để chạy command tuỳ ý, miễn schema nạp từ đâu đó attacker chạm tới được.

Technical facts

Thay vì interpret schema tại runtime, protobuf.js compile schema thành hàm JS để tối ưu tốc độ. Helper nằm ở lib/codegen/index.js, ghép nối JS source bằng concatenation và đưa cho Function(). Function(source) về bản chất là eval() đổi tên: tham số được parse và thực thi như code JS tươi.

Điểm chèn là tham số functionName — chính là tên type lấy thẳng từ descriptor. Không escape, không validator. Với schema JSON do attacker cung cấp, name đi thẳng vào slot "function " + functionName + "(".

PoC trong advisory đặt tên type như sau:

User){process.mainModule.require("child_process").execSync("id"); function x(

Chuỗi này đóng signature hàm tổng hợp, inline payload execSync("id"), và mở một hàm rỗng để cân brace đuôi. Function vui vẻ parse và chạy toàn bộ.

Thuộc tínhChi tiết
CVE IDCVE-2026-41242
GHSAGHSA-xq3m-2v4x-88gg
CVSS 4.09.4 (Critical)
CWECWE-94 (Code Injection)
VectorAV:N/AC:L/PR:L/UI:N — network, low complexity, không UI
Affectedprotobufjs ≤ 8.0.0 và ≤ 7.5.4
Patched8.0.1, 7.5.5
Weekly downloads~52 triệu/npm
EPSS0.05% (chưa thấy exploit in-the-wild)

Một chi tiết quan trọng: constructor sinh lazy. Gọi Root.fromJSON(malicious) một mình không kích hoạt payload. Phải đến khi app gọi root.lookupType(...).decode(buffer) lần đầu với type độc — đây là lý do lỗi đe doạ app đang chạy production, không phải build pipeline.

Comparison

Vụ này cùng họ với các sự cố codegen gần đây (Orval — GHSA-mwr6-3gp8-9jmj, GHSA-h526-wf6g-67jv; eslint-scope): chuỗi không tin cậy được nối vào template rồi compile thành code. Khác biệt quan trọng:

  • Orval / eslint-scope: kích hoạt tại build time, trên máy dev hoặc CI runner (nơi có SSH keys, cloud creds, publishing tokens).
  • protobuf.js: kích hoạt tại runtime, trong service tiếp xúc user/partner (nơi có service tokens, user data, KMS secrets).

Cũng cần phân biệt với CVE-2023-36665 (prototype pollution trong protobufjs): lỗi cũ làm hỏng state object; CVE-2026-41242 là code injection trực tiếp vào function compiled — nghiêm trọng hơn rõ rệt.

Use cases & attack scenarios

  • gRPC server self-describe: client như grpcurl, Postman gRPC, Kreya, BloomRPC dùng ServerReflection để lấy schema. Một rogue/compromised gRPC server đẩy descriptor độc — client decode là dính.
  • Multi-tenant SaaS: analytics, iPaaS, observability, data pipeline cho khách upload descriptor — một descriptor độc + traffic event bình thường = RCE trên ingestion tier.
  • API gateway / service mesh: gateway load .proto để decode routing. Schema poison biến gateway thành môi trường thực thi của attacker.
  • Schema registry nội bộ: một tài khoản dev bị compromise = RCE trên mọi service decode theo schema đó.
  • Reverse-engineering: dev tải .proto từ gist/Slack DM để debug traffic — decode một message mẫu là dính ngay trên máy local.

Limitations & mitigation

Lỗi chỉ kích hoạt khi attacker ảnh hưởng được tới schema app nạp. App chỉ load .proto do team tự viết, version-controlled, nằm ngoài threat model. Nhưng habit tái sử dụng schema (Buf Schema Registry, googleapis/googleapis, envoyproxy/envoy/api, cncf/xds) khiến điều kiện này dễ xảy ra hơn nhiều người nghĩ.

Patch upstream (PR #2127, commit 535df44) chỉ thêm một dòng regex trong Type constructor của src/type.js: strip mọi ký tự ngoài [A-Za-z0-9_] khỏi tên type trước khi đi vào codegen. Đơn giản, đủ để loại bỏ mọi token (parentheses, braces, semicolons, quotes, whitespace) mà attacker cần để đóng signature.

Remediation:

  • Nâng ngay protobufjs@^8.0.1 hoặc ^7.5.5.
  • Chạy npm ls protobufjsnpm audit để lộ transitive pulls qua @grpc/proto-loader, Firebase, Google Cloud client.
  • Coi Root.fromJSON, load, parse trên bytes tuỳ ý như eval trên bytes tuỳ ý.
  • Trong production, ưu tiên artifact tĩnh (pbjs, pbts) thay vì compile descriptor runtime.
  • Pin và verify checksum của schema reuse; review .proto như review npm dependency mới.

What's next

Bài học kiến trúc mà Endor Labs nhấn mạnh: fix regex là remediation đúng trong ngắn hạn, nhưng fix dài hạn phải là bỏ hẳn việc nhét identifier từ attacker vào Function() — chuyển sang emit code tra cứu qua dispatch table an toàn, key bằng identifier đã sanitize.

Ngoài ra, cần đối xử với comment // eslint-disable-line no-new-func, no-eval, security/detect-* như cờ audit, không phải đèn xanh. Hai lần suppress trên hai call site nguy hiểm nhất đã che lỗ hổng này nhiều năm.

Supply-chain không còn chỉ là npm package bị chiếm — làn sóng mới là feed dữ liệu độc vào tool hợp pháp (template engines, codegen, schema compiler, linter với AST rewriter, notebook kernel, LSP server, build plugin). Protobuf.js là mẫu điển hình của pattern "data → dynamic code gen → execution" — pattern này giờ là mặc định, không phải ngoại lệ, trong dev tooling hiện đại.

Nguồn: Endor Labs, BleepingComputer, GitHub Advisory GHSA-xq3m-2v4x-88gg, CIRCL Vulnerability Lookup.