Reject WebCrypto cipher operations whose computed output length would
exceed INT_MAX before passing the length to OpenSSL.
This avoids signed overflow in the AES and ChaCha20-Poly1305 one-shot
cipher paths and turns oversized inputs into a clean operation failure.
Refs: https://hackerone.com/reports/
3760016
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Backport-PR-URL: https://github.com/nodejs-private/node-private/pull/879
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs-private/node-private/pull/878
CVE-ID: CVE-2026-48933
origin: backport, https://github.com/nodejs/node/commit/
38b4c5ed51b2ec81c28fbd379fea72e22fa12a15
bug: https://nodejs.org/en/blog/vulnerability/june-2026-security-releases#nodejs-webcrypto-aes-integer-overflow-leads-to-remote-process-abort-dos-cve-2026-48933---high
Gbp-Pq: Topic sec
Gbp-Pq: Name CVE-2026-48933.patch
}
size_t total = 0;
- int buf_len = in.size() + EVP_CIPHER_CTX_block_size(ctx.get()) + tag_len;
+ const int block_size = EVP_CIPHER_CTX_block_size(ctx.get());
+ if (block_size < 0) {
+ return WebCryptoCipherStatus::FAILED;
+ }
+ int buf_len;
+ if (!TryGetIntCipherOutputLength(
+ in.size(), static_cast<size_t>(block_size) + tag_len, &buf_len)) {
+ return WebCryptoCipherStatus::FAILED;
+ }
int out_len;
if (mode == EVP_CIPH_GCM_MODE &&
total += out_len;
CHECK_LE(out_len, buf_len);
- out_len = EVP_CIPHER_CTX_block_size(ctx.get());
+ out_len = block_size;
if (!EVP_CipherFinal_ex(
ctx.get(), buf.data<unsigned char>() + total, &out_len)) {
return WebCryptoCipherStatus::FAILED;
#include "memory_tracker.h"
#include "v8.h"
+#include <climits>
#include <string>
namespace node {
FAILED
};
+inline bool TryGetIntCipherOutputLength(size_t input_len,
+ size_t output_overhead,
+ int* output_len) {
+ static constexpr size_t kMaxLength = INT_MAX;
+ if (output_overhead > kMaxLength ||
+ input_len > kMaxLength - output_overhead) {
+ return false;
+ }
+ *output_len = static_cast<int>(input_len + output_overhead);
+ return true;
+}
+
// CipherJob is a base implementation class for implementations of
// one-shot sync and async ciphers. It has been added primarily to
// support the AES and RSA ciphers underlying the WebCrypt API.
// and setting it to a file that does not exist.
#define NODE_OPENSSL_SYSTEM_CERT_PATH "/missing/ca.pem"
+#include "crypto/crypto_cipher.h"
#include "crypto/crypto_context.h"
+#include "gtest/gtest.h"
#include "node_options.h"
#include "openssl/err.h"
-#include "gtest/gtest.h"
+
+#include <climits>
/*
* This test verifies that a call to NewRootCertDir with the build time
"any errors on the OpenSSL error stack\n";
X509_STORE_free(store);
}
+
+TEST(NodeCrypto, TryGetIntCipherOutputLength) {
+ int output_len = 0;
+
+ EXPECT_TRUE(
+ node::crypto::TryGetIntCipherOutputLength(INT_MAX - 16, 16, &output_len));
+ EXPECT_EQ(output_len, INT_MAX);
+
+ EXPECT_FALSE(
+ node::crypto::TryGetIntCipherOutputLength(INT_MAX - 15, 16, &output_len));
+
+ EXPECT_FALSE(node::crypto::TryGetIntCipherOutputLength(
+ 0, static_cast<size_t>(INT_MAX) + 1, &output_len));
+}