-
Notifications
You must be signed in to change notification settings - Fork 614
Expand file tree
/
Copy pathCVE-2026-21710.patch
More file actions
152 lines (142 loc) · 5.48 KB
/
CVE-2026-21710.patch
File metadata and controls
152 lines (142 loc) · 5.48 KB
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
From b046ea0fa85136ebb2a112360690650f827eb94c Mon Sep 17 00:00:00 2001
From: Matteo Collina <hello@matteocollina.com>
Date: Thu, 19 Feb 2026 15:49:43 +0100
Subject: [PATCH] http: use null prototype for headersDistinct/trailersDistinct
Use { __proto__: null } instead of {} when initializing the
headersDistinct and trailersDistinct destination objects.
A plain {} inherits from Object.prototype, so when a __proto__
header is received, dest["__proto__"] resolves to Object.prototype
(truthy), causing _addHeaderLineDistinct to call .push() on it,
which throws an uncaught TypeError and crashes the process.
Ref: https://hackerone.com/reports/3560402
PR-URL: https://github.com/nodejs-private/node-private/pull/821
Refs: https://hackerone.com/reports/3560402
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
CVE-ID: CVE-2026-21710
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/nodejs/node/commit/00ad47a28e.patch
---
lib/_http_incoming.js | 4 +--
.../test-http-headers-distinct-proto.js | 36 +++++++++++++++++++
test/parallel/test-http-multiple-headers.js | 16 ++++-----
3 files changed, 46 insertions(+), 10 deletions(-)
create mode 100644 test/parallel/test-http-headers-distinct-proto.js
diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js
index e45ae819..77433e55 100644
--- a/lib/_http_incoming.js
+++ b/lib/_http_incoming.js
@@ -131,7 +131,7 @@ ObjectDefineProperty(IncomingMessage.prototype, 'headersDistinct', {
__proto__: null,
get: function() {
if (!this[kHeadersDistinct]) {
- this[kHeadersDistinct] = {};
+ this[kHeadersDistinct] = { __proto__: null };
const src = this.rawHeaders;
const dst = this[kHeadersDistinct];
@@ -171,7 +171,7 @@ ObjectDefineProperty(IncomingMessage.prototype, 'trailersDistinct', {
__proto__: null,
get: function() {
if (!this[kTrailersDistinct]) {
- this[kTrailersDistinct] = {};
+ this[kTrailersDistinct] = { __proto__: null };
const src = this.rawTrailers;
const dst = this[kTrailersDistinct];
diff --git a/test/parallel/test-http-headers-distinct-proto.js b/test/parallel/test-http-headers-distinct-proto.js
new file mode 100644
index 00000000..bd4cb82b
--- /dev/null
+++ b/test/parallel/test-http-headers-distinct-proto.js
@@ -0,0 +1,36 @@
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const http = require('http');
+const net = require('net');
+
+// Regression test: sending a __proto__ header must not crash the server
+// when accessing req.headersDistinct or req.trailersDistinct.
+
+const server = http.createServer(common.mustCall((req, res) => {
+ const headers = req.headersDistinct;
+ assert.strictEqual(Object.getPrototypeOf(headers), null);
+ assert.deepStrictEqual(Object.getOwnPropertyDescriptor(headers, '__proto__').value, ['test']);
+ res.end();
+}));
+
+server.listen(0, common.mustCall(() => {
+ const port = server.address().port;
+
+ const client = net.connect(port, common.mustCall(() => {
+ client.write(
+ 'GET / HTTP/1.1\r\n' +
+ 'Host: localhost\r\n' +
+ '__proto__: test\r\n' +
+ 'Connection: close\r\n' +
+ '\r\n',
+ );
+ }));
+
+ client.on('end', common.mustCall(() => {
+ server.close();
+ }));
+
+ client.resume();
+}));
diff --git a/test/parallel/test-http-multiple-headers.js b/test/parallel/test-http-multiple-headers.js
index 1ebd290a..1188af5d 100644
--- a/test/parallel/test-http-multiple-headers.js
+++ b/test/parallel/test-http-multiple-headers.js
@@ -27,13 +27,13 @@ const server = createServer(
host,
'transfer-encoding': 'chunked'
});
- assert.deepStrictEqual(req.headersDistinct, {
+ assert.deepStrictEqual(req.headersDistinct, Object.assign({ __proto__: null }, {
'connection': ['close'],
'x-req-a': ['eee', 'fff', 'ggg', 'hhh'],
'x-req-b': ['iii; jjj; kkk; lll'],
'host': [host],
- 'transfer-encoding': ['chunked']
- });
+ 'transfer-encoding': ['chunked'],
+ }));
req.on('end', function() {
assert.deepStrictEqual(req.rawTrailers, [
@@ -46,7 +46,7 @@ const server = createServer(
);
assert.deepStrictEqual(
req.trailersDistinct,
- { 'x-req-x': ['xxx', 'yyy'], 'x-req-y': ['zzz; www'] }
+ Object.assign({ __proto__: null }, { 'x-req-x': ['xxx', 'yyy'], 'x-req-y': ['zzz; www'] })
);
res.setHeader('X-Res-a', 'AAA');
@@ -129,14 +129,14 @@ server.listen(0, common.mustCall(() => {
'x-res-d': 'JJJ; KKK; LLL',
'transfer-encoding': 'chunked'
});
- assert.deepStrictEqual(res.headersDistinct, {
+ assert.deepStrictEqual(res.headersDistinct, Object.assign({ __proto__: null }, {
'x-res-a': [ 'AAA', 'BBB', 'CCC' ],
'x-res-b': [ 'DDD; EEE; FFF; GGG' ],
'connection': [ 'close' ],
'x-res-c': [ 'HHH', 'III' ],
'x-res-d': [ 'JJJ; KKK; LLL' ],
- 'transfer-encoding': [ 'chunked' ]
- });
+ 'transfer-encoding': [ 'chunked' ],
+ }));
res.on('end', function() {
assert.deepStrictEqual(res.rawTrailers, [
@@ -150,7 +150,7 @@ server.listen(0, common.mustCall(() => {
);
assert.deepStrictEqual(
res.trailersDistinct,
- { 'x-res-x': ['XXX', 'YYY'], 'x-res-y': ['ZZZ; WWW'] }
+ Object.assign({ __proto__: null }, { 'x-res-x': ['XXX', 'YYY'], 'x-res-y': ['ZZZ; WWW'] })
);
server.close();
});
--
2.45.4