A HashDoS (hash-collision denial of service), also called hash flooding, is a Layer 7 (application) attack vector that exploits the hash tables buried inside web frameworks, one of the algorithmic-complexity classes a thorough DDoS test is built to exercise. The attacker submits a single POST body or JSON payload carrying thousands of parameter keys chosen to collide into the same hash bucket. The hash table that should give O(1) inserts degrades to O(n squared) scanning, and one ordinary-looking request pins a CPU core for seconds.
How hash flooding works
When a framework parses a form body or a JSON object, it loads each key into a hash map. A healthy hash map spreads keys across many buckets, so lookups and inserts are effectively constant time. That guarantee holds only while the keys are unpredictable. If the hash function is deterministic and publicly known, an attacker can precompute a set of distinct keys that all hash to the same bucket.
Every colliding key then lands in the same bucket's chain, and each insert has to walk the growing chain to check for duplicates. Inserting n such keys costs on the order of n squared operations. A payload of a few tens of thousands of parameters, well within a normal request-size limit, turns into billions of comparisons. The class was disclosed broadly in 2011 and affected the default parsers of PHP, Java, Python, Ruby, and ASP.NET at once, because they shared the same predictable hashing.
Why it matters under attack
HashDoS shares the brutal asymmetry of ReDoS: a tiny, cheap request against an expensive server operation. The request rate is negligible, so volumetric and rate-limit controls tuned for packets-per-second stay quiet. Like any application-layer attack, the payload is a well-formed POST that looks entirely legitimate on the wire, and deep packet inspection has no signature for "these particular keys happen to collide."
The CPU spike arrives before the application logic even runs, during parsing, so guards placed deeper in the request path never get a turn. On an autoscaled tier the platform reacts to the load by adding instances, so an attack that should have been a brief outage becomes sustained spend, the autoscaler-exposure failure mode where the bill absorbs the attack instead of the service falling over.
What a DDoS test measures
The defenses are specific and checkable, so a test asks specific questions. Is hash randomization enabled, so the collision set an attacker precomputes does not line up with the server's live seed. Is there a cap on the number of parameters a single request may carry, such as PHP's max_input_vars. Are request-body sizes bounded before the parser allocates. And is there a per-request CPU budget that ends a pathological parse instead of letting it run to completion.
The result is a measurement of goodput under a payload engineered to be maximally expensive to parse: how many crafted requests it takes before real users lose service, and whether the platform sheds them or silently scales to meet them.
How the frameworks fixed it, and what remains
The language-level response was to make the hash unpredictable. Modern runtimes seed their string hash with a random value per process, many using SipHash, so an attacker cannot precompute a colliding set that lines up with the live seed. Alongside randomization, the platforms capped the number of parameters a request may carry, turning an unbounded n squared into a bounded, survivable cost.
Neither fix is automatic in the field. Randomization can be disabled for reproducibility, legacy services run interpreters that predate the patch, and custom parsers or ad-hoc hash maps in application code reintroduce the predictable hashing the runtime worked to remove. The residual risk lives wherever untrusted structured input meets a hash table nobody remembered to harden. For how this vector fits a structured resilience exercise, see DDoS resilience testing.
Hash flooding is old, patched at the language level years ago, and still live wherever a service parses untrusted structured input with randomization disabled or a parameter cap set too high. The lesson outlasts the specific CVEs: any data structure whose performance depends on unpredictable inputs becomes attack surface the moment the inputs stop being unpredictable.