Live › vulnerability › VND-nodejs-march-2026-hashdos
Go to dashboardV8 hashes array-index-looking strings with a fixed, unseeded function, so an attacker can predict collisions and craft inputs that stall the event loop. A remote client sending a crafted JSON payload to a Node.js server can cause severe slowdowns or a sustained denial of service.
Summary written from the sources below. Check the originals before acting.
First seen by InfraStack 2026-10-23 19:13 UTC. All times on this page are UTC.
Servers built on Node.js that parse or store untrusted input, such as JSON from clients or object keys built from request data, are exposed because V8 uses the same string table and Map internals for these values. Browser use is not considered a vulnerability in this context. Teams that only run Node.js on trusted internal data may skip it.
| Product | Ecosystem | Affected | Fixed in |
|---|---|---|---|
| node | node | – | – |
node --version and compare against the patched releases listed in the Node.js March 2026 security release notes.Each row is the first time that source carried this signal. The analyst’s rows are its own findings.
Commercial support for versions past the Maintenance LTS phase is available through our OpenJS Ecosystem Sustainability Program partners Developing a minimally HashDoS resistant, yet quickly reversible integer hash for V8 JC Joyee Cheung Developing a minimally HashDoS resistant, yet quickly reversible integer hash for V8 What happens when a hashing scheme needs to be both HashDoS resistant and quickly reversible? That's the puzzle we tried to solve for addressing CVE-2026-21717 in the March 2026 Node.js security release . This led to the development of an integer hash that we believe is unpredictable enough to prevent a blind attacker from reliably triggering severe performance degradation in our threat model. At the same time, it is also a permutation that can be efficiently inverted to recover the original integer value by the runtime holding the secret random keys, which is important for maintaining V8's performance optimizations. In this post, we will go into the details of this vulnerability, explain why and how the design tried to meet the two seemingly contradictory requirements, and sample the statistical analysis we performed to evaluate the quality of the hash. Along the way, we will also discuss some specifics of how V8 stores and uses string hashes internally that lead to these constraints, the implementation techniques, and the performance analysis. What is HashDoS and why does it matter for Node.js? Hash tables are one of the most important data structures in software, and Node.js/V8 are no exceptions. With hash tables, there comes the problem of collisions - while hash tables are designed to have O(1) average time complexity for, e.g., single lookup and insertion, when there are so many keys whose hashed values can be mapped to the same slot that the table has to walk through many locations to insert a new key, it's theoretically possible to degrade to O(n 2 ) in total for inserting n keys. In many applications, the worst-case performance of hash tables is usually just a theoretical concern and maybe an occasional nuisance, but for servers that need to process untrusted input, this can be an attack vector. If an attacker manages to find a path that allows them to cause a large number of collisions in the server's internal hash table with a small number of inputs, they can effectively "freeze" the thread without much effort. And, with enough threads frozen, they could render the service unavailable for a sustained period of time. This is commonly called a hash flooding or Hash-DoS (Denial of Service) attack . HashDoS vulnerabilities can show up in a wide range of platforms. In the case of V8, when it's used in a browser, DoS issues are not considered vulnerabilities because they typically only affect the tab that processes the malicious input, and users can simply close the tab. But when it's used in event-loop-based server-side runtimes, a single malicious request that manages to block the entire event loop for a sustained period of time has a much bigger impact. As one of the most widely deployed server-side runtimes, Node.js draws extensive scrutiny from security researchers, which helps us find and address weak spots like these. Unlike other DoS attack vectors that can be more easily mitigated by userland restrictions, HashDoS vulnerabilities are particularly tricky because they lurk inside widely used internal data structures and well-defined operations trusted by developers. For V8 embedders, this means fixes for HashDoS vulnerabilities usually fall on the runtime maintainers, and they are a critical part of maintaining the security and reliability of the ecosystem. Mitigating HashDoS with seeded hashes The core of HashDoS vulnerabilities lies in deterministic hash functions - if the attacker can predict the hash values of their inputs, they can craft inputs that reliably trigger worst-case performance in the target server. The standard mitigation is to mix a seed value into the computation of the hash, and make sure that the seed is randomly generated at program initialization . This way, even if the attacker knows the hash function, they can't predict the hash values without knowing the seed that changes whenever the server restarts, and therefore can't craft inputs that will reliably collide. In Node.js/V8, HashDoS vulnerabilities tend to center around misconfigurations that lead to unseeded hashes or hashes seeded by a constant value. For an early history of HashDoS vulnerabilities in Node.js/V8 and their mitigations, check out this V8 blog post . A more recent example is CVE-2025-27209 , reported by Mate Marjanović and addressed in Node.js's July 2025 security release: during V8's switch to rapidhash , a configuration gap left the constants used by rapidhash hard-coded in V8 without seeding. To mitigate this, Node.js temporarily reverted back to a seeded hash in its copy of V8. Later, Gus Caplan from Deno ported rapidhash's secret generation code to V8 and wired it up to seed the constants used by rapidhash at runtime , which became the eventual mitigation that shipped in newer versions of Node.js. The generation of rapidhash secrets turned out to be important to our later design for the seeded integer hash, which we will discuss below. Until recently, most HashDoS discoveries in V8 had centered on hashing of regular strings, since they are more commonly found in paths exposed to server handlers. It wasn't until the recent HackerOne report by Mate Marjanović that our attention was drawn to an elephant in the room: array index strings (those that look like non-negative integers and fit within 24 bits) in V8 used a different deterministic hash that can be trivially predicted. What string hashes look like in V8 To understand the vulnerability, let's look at how V8 stores string hashes internally. Every v8::internal::Name object (the superclass of v8::internal::String in V8) carries a 32-bit raw_hash_field . The composition of this field varies depending on the type of string. The bottom 2 bits ( HashFieldTypeBits ) determine the interpretation, and two of the most common types are: Regular strings (type kHash = 0b10 ): bits 2-31 store a 30-bit hash value computed by rapidhash, seeded with randomly generated secrets. This is considered to be "minimally HashDoS resistant" , which we will discuss later. Array index strings (type kIntegerIndex = 0b00 ): these are decimal-integer-looking strings whose numeric value fits in 24 bits. bits 2-25 (24 bits) hold the numeric value of the integer ( ArrayIndexValueBits ), and bits 26-31 (6 bits) hold the string length ( ArrayIndexLengthBits ). The layout of the hash fields looks like this (the least significant bits are on the right): "hello" (type: kHash = 0b10): +-----------------------------------+---+ | 30-bit rapidhash |1 0| +-----------------------------------+---+ 31 2 1 0 "1234" (length=4, value=1234, type: kIntegerIndex = 0b00): +--------+--------------------------+---+ | 000100 | 000000000000010011010010 |0 0| | length | numeric value | | +--------+--------------------------+---+ 31 26 25 2 1 0 As you can see, the hash for array index strings is fully deterministic and there's no seeding involved. An attacker can easily predict their hash values, and with a bit of effort, craft colliding inputs. Exploiting the deterministic hash for array index strings One of the most commonly used hash tables in V8 is the string table , which is used for string internalization - deduplicating and caching strings in a global table for time and memory efficiency. The string table uses open addressing with quadratic probing to deal with collisions. The probing sequence is: slot 0 = hash & ( capacity - 1 ) , capacity = 2 n slot k = ( slot k - 1 + k ) & ( capacity - 1 ) = ( slot k - 1 + k ) ( mod capacity ) The string table grows by adding 50% slack and rounding the capacity to a power
This page as .md · .json · in your agent: get_signal("VND-nodejs-march-2026-hashdos")