Memory safety (heap allocation/use-after-free risk in Latin1 path of Buffer.indexOf)

HIGH
nodejs/node
Commit: f08e2e06eb38
Affected: < 25.9.0
2026-04-05 10:18 UTC

Description

The commit fixes a memory safety issue in the Latin1 path of Buffer.indexOf. Previously, IndexOfString used a heap allocation (UncheckedMalloc) for the needle in the LATIN1 branch, with an explicit free. If allocation failed or due to edge-case error handling, this path could be prone to memory-management bugs such as use-after-free or double-free scenarios. The patch replaces the heap allocation with MaybeStackBuffer, removing the explicit free and relying on stack allocation when possible, with a heap fallback managed by MaybeStackBuffer. This reduces memory-management risks in a hot path and improves overall memory safety for the Latin1 indexOf operation.

Commit Details

Author: Mert Can Altin

Date: 2026-03-17 20:27 UTC

Message:

src: use stack allocation in indexOf latin1 path PR-URL: https://github.com/nodejs/node/pull/62268 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Daniel Lemire <daniel@lemire.me>

Triage Assessment

Vulnerability Type: Memory safety

Confidence: HIGH

Reasoning:

The commit replaces a heap allocation (UncheckedMalloc) and manual free with a stack-allocated buffer (MaybeStackBuffer) for the LATIN1 path in IndexOfString. This reduces memory-management risks (e.g., allocation failure handling, double free, use-after-free) and mitigates potential memory-safety vulnerabilities in that path. Although not a conventional vulnerability like XSS/SQLi, it improves memory safety which is a common security concern.

Verification Assessment

Vulnerability Type: Memory safety (heap allocation/use-after-free risk in Latin1 path of Buffer.indexOf)

Confidence: HIGH

Affected Versions: < 25.9.0

Code Diff

diff --git a/benchmark/buffers/buffer-indexof.js b/benchmark/buffers/buffer-indexof.js index 52cc95ccb9cf7e..be6cc243a975da 100644 --- a/benchmark/buffers/buffer-indexof.js +++ b/benchmark/buffers/buffer-indexof.js @@ -19,7 +19,7 @@ const searchStrings = [ const bench = common.createBenchmark(main, { search: searchStrings, - encoding: ['undefined', 'utf8', 'ucs2'], + encoding: ['undefined', 'utf8', 'ucs2', 'latin1'], type: ['buffer', 'string'], n: [5e4], }, { diff --git a/src/node_buffer.cc b/src/node_buffer.cc index e40a21288ee79d..acf4aff37c5a9c 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -1051,23 +1051,19 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) { offset, is_forward); } else if (enc == LATIN1) { - uint8_t* needle_data = node::UncheckedMalloc<uint8_t>(needle_length); - if (needle_data == nullptr) { - return args.GetReturnValue().Set(-1); - } + MaybeStackBuffer<uint8_t> needle_data(needle_length); StringBytes::Write(isolate, - reinterpret_cast<char*>(needle_data), + reinterpret_cast<char*>(needle_data.out()), needle_length, needle, enc); result = nbytes::SearchString(reinterpret_cast<const uint8_t*>(haystack), haystack_length, - needle_data, + needle_data.out(), needle_length, offset, is_forward); - free(needle_data); } args.GetReturnValue().Set(
← Back to Alerts View on GitHub →