thrift: fix multiple CVEs

CVE-2026-43868:
  Memory Allocation with Excessive Size Value vulnerability in Apache Thrift.

CVE-2026-43869:
  Improper Validation of Certificate with Host Mismatch vulnerability in Apache Thrift.
  This CVE only affects the Java client, which is not built by the recipe. Marked as
  'not-applicable-config'.
  Upstream commit:
    https://github.com/apache/thrift/commit/a30c552bd0808b7e19f35ad30212ba7a9aee8c66

CVE-2026-43870:
  Origin Validation Error, Improper Limitation of a Pathname to a Restricted Directory
  ('Path Traversal'), Improper Neutralization of CRLF Sequences in HTTP Headers
  ('HTTP Request/Response Splitting'), Uncontrolled Resource Consumption vulnerability
  in Apache Thrift.

Signed-off-by: Roland Kovacs <roland.kovacs@est.tech>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
Roland Kovacs
2026-07-07 15:09:19 +02:00
committed by Anuj Mittal
parent d97b5602d7
commit 0a044f3363
3 changed files with 1519 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,134 @@
From 86f647c6894360da7496efee6f6f5eb2601a5c3f Mon Sep 17 00:00:00 2001
From: Jens Geyer <jensg@apache.org>
Date: Sat, 11 Apr 2026 12:29:16 +0200
Subject: [PATCH] Harden Node.js WebSocket server handling Client: nodejs
- Validate origin on WebSocket upgrade using the same CORS rules
as HTTP requests
- Fix path containment check to use trailing separator
- Replace deprecated new Buffer() with Buffer.alloc()
- Sanitize interpolated header values in upgrade response
(04)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This closes #3391
CVE: CVE-2026-43870
Upstream-Status: Backport [https://github.com/apache/thrift/commit/5e4f01d737e4d3845d07dde6da43981feee0cb9a]
Signed-off-by: Roland Kovacs <roland.kovacs@est.tech>
---
lib/nodejs/lib/thrift/web_server.js | 34 +++++++++++++++++++++--------
1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/lib/nodejs/lib/thrift/web_server.js b/lib/nodejs/lib/thrift/web_server.js
index f49f654b1..ad3a34c5c 100644
--- a/lib/nodejs/lib/thrift/web_server.js
+++ b/lib/nodejs/lib/thrift/web_server.js
@@ -27,6 +27,10 @@ var log = require("./log");
var MultiplexedProcessor =
require("./multiplexed_processor").MultiplexedProcessor;
+function sanitizeHeader(value) {
+ return (value || "").replace(/[\r\n]/g, "");
+}
+
var TBufferedTransport = require("./buffered_transport");
var TBinaryProtocol = require("./binary_protocol");
var InputBufferUnderrunError = require("./input_buffer_underrun_error");
@@ -84,7 +88,7 @@ var wsFrame = {
* @returns {Buffer} - The WebSocket frame, ready to send
*/
encode: function (data, mask, binEncoding) {
- var frame = new Buffer(wsFrame.frameSizeFromData(data, mask));
+ var frame = Buffer.alloc(wsFrame.frameSizeFromData(data, mask));
//Byte 0 - FIN & OPCODE
frame[0] =
wsFrame.fin.FIN +
@@ -171,19 +175,19 @@ var wsFrame = {
}
//MASK
if (wsFrame.mask.TO_SERVER == (frame[1] & wsFrame.mask.TO_SERVER)) {
- result.mask = new Buffer(4);
+ result.mask = Buffer.alloc(4);
frame.copy(result.mask, 0, dataOffset, dataOffset + 4);
dataOffset += 4;
}
//Payload
- result.data = new Buffer(len);
+ result.data = Buffer.alloc(len);
frame.copy(result.data, 0, dataOffset, dataOffset + len);
if (result.mask) {
wsFrame.applyMask(result.data, result.mask);
}
//Next Frame
if (frame.length > dataOffset + len) {
- result.nextFrame = new Buffer(frame.length - (dataOffset + len));
+ result.nextFrame = Buffer.alloc(frame.length - (dataOffset + len));
frame.copy(result.nextFrame, 0, dataOffset + len, frame.length);
}
//Don't forward control frames
@@ -450,7 +454,8 @@ exports.createWebServer = function (options) {
var filename = path.resolve(path.join(baseDir, uri));
//Ensure the basedir path is not able to be escaped
- if (filename.indexOf(baseDir) != 0) {
+ var normalizedBase = baseDir.endsWith(path.sep) ? baseDir : baseDir + path.sep;
+ if (filename !== baseDir && filename.indexOf(normalizedBase) !== 0) {
response.writeHead(400, "Invalid request path", {});
response.end();
return;
@@ -543,6 +548,14 @@ exports.createWebServer = function (options) {
}
})
.on("upgrade", function (request, socket, head) {
+ //Verify CORS origin for WebSocket upgrades
+ if (request.headers.origin && options.cors) {
+ if (!options.cors["*"] && !options.cors[request.headers.origin]) {
+ socket.write("HTTP/1.1 403 Origin not allowed\r\n\r\n");
+ socket.destroy();
+ return;
+ }
+ }
//Lookup service
var svc;
try {
@@ -557,6 +570,9 @@ exports.createWebServer = function (options) {
request.headers["sec-websocket-key"] +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
);
+ var origin = sanitizeHeader(request.headers.origin);
+ var host = sanitizeHeader(request.headers.host);
+ var reqUrl = sanitizeHeader(request.url);
socket.write(
"HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
@@ -565,11 +581,11 @@ exports.createWebServer = function (options) {
hash.digest("base64") +
"\r\n" +
"Sec-WebSocket-Origin: " +
- request.headers.origin +
+ origin +
"\r\n" +
"Sec-WebSocket-Location: ws://" +
- request.headers.host +
- request.url +
+ host +
+ reqUrl +
"\r\n" +
"\r\n",
);
@@ -582,7 +598,7 @@ exports.createWebServer = function (options) {
//Prepend any existing decoded data
if (data) {
if (result.data) {
- var newData = new Buffer(data.length + result.data.length);
+ var newData = Buffer.alloc(data.length + result.data.length);
data.copy(newData);
result.data.copy(newData, data.length);
result.data = newData;
--
2.34.1
@@ -11,6 +11,8 @@ DEPENDS = "thrift-native boost flex-native bison-native openssl zlib"
SRC_URI = "https://downloads.apache.org/${BPN}/${PV}/${BP}.tar.gz \
file://0001-DefineInstallationPaths.cmake-Define-libdir-in-terms.patch \
file://0001-support-reproducible-builds.patch \
file://CVE-2026-43868.patch \
file://CVE-2026-43870.patch \
"
SRC_URI[sha256sum] = "794a0e455787960d9f27ab92c38e34da27e8deeda7a5db0e59dc64a00df8a1e5"
@@ -18,6 +20,8 @@ BBCLASSEXTEND = "native nativesdk"
CVE_PRODUCT = "apache:thrift"
CVE_STATUS[CVE-2026-43869] = "not-applicable-config: The issue is present in the Java client which is not built"
inherit pkgconfig cmake python3native
export STAGING_INCDIR