GHSA-PC3F-X583-G7J2
Vulnerability from github – Published: 2026-04-16 20:44 – Updated: 2026-04-16 20:44The SPDY/3 frame parser in spdystream does not validate
attacker-controlled counts and lengths before allocating memory. A
remote peer that can send SPDY frames to a service using spdystream can
cause the process to allocate gigabytes of memory with a small number of
malformed control frames, leading to an out-of-memory crash.
Three allocation paths in the receive side are affected:
1. SETTINGS entry count -- The SETTINGS frame reader reads a 32-bit
numSettings from the payload and allocates a slice of that size
without checking it against the declared frame length. An attacker
can set numSettings to a value far exceeding the actual payload,
triggering a large allocation before any setting data is read.
2. Header count -- parseHeaderValueBlock reads a 32-bit
numHeaders from the decompressed header block and allocates an
http.Header map of that size with no upper bound.
3. Header field size -- Individual header name and value lengths are
read as 32-bit integers and used directly as allocation sizes with
no validation.
Because SPDY header blocks are zlib-compressed, a small on-the-wire
payload can decompress into attacker-controlled bytes that the parser
interprets as 32-bit counts and lengths. A single crafted frame is
enough to exhaust process memory.
Impact
Any program that accepts SPDY connections using spdystream -- directly or through a dependent library -- is affected. A remote peer that can send SPDY frames to the service can crash the process with a single crafted SPDY control frame, causing denial of service.
Affected versions
github.com/moby/spdystream <= v0.5.0
Fix
v0.5.1 addresses the receive-side allocation bugs and adds related
hardening:
Core fixes:
- SETTINGS entry-count validation -- The SETTINGS frame reader now
checks that numSettings is consistent with the declared frame
length (numSettings <= (length-4)/8) before allocating.
- Header count limit -- parseHeaderValueBlock enforces a maximum
number of headers per frame (default: 1000).
- Header field size limit -- Individual header name and value
lengths are checked against a per-field size limit (default: 1 MiB)
before allocation.
- Connection closure on protocol error -- The connection read loop
now closes the underlying net.Conn when it encounters an
InvalidControlFrame error, preventing further exploitation on the
same connection.
Additional hardening:
- Write-side bounds checks -- All frame write methods now verify
that payloads fit within the 24-bit length field, preventing the
library from producing invalid frames.
Configurable limits:
- Callers can adjust the defaults using NewConnectionWithOptions or
the lower-level spdy.NewFramerWithOptions with functional options:
WithMaxControlFramePayloadSize, WithMaxHeaderFieldSize, and
WithMaxHeaderCount.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.5.0"
},
"package": {
"ecosystem": "Go",
"name": "github.com/moby/spdystream"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.5.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-35469"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-16T20:44:01Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "The SPDY/3 frame parser in spdystream does not validate\nattacker-controlled counts and lengths before allocating memory. A\nremote peer that can send SPDY frames to a service using spdystream can\ncause the process to allocate gigabytes of memory with a small number of\nmalformed control frames, leading to an out-of-memory crash.\n\u00a0\nThree allocation paths in the receive side are affected:\n1. **SETTINGS entry count** -- The SETTINGS frame reader reads a 32-bit\n`numSettings` from the payload and allocates a slice of that size\nwithout checking it against the declared frame length. An attacker\ncan set `numSettings` to a value far exceeding the actual payload,\ntriggering a large allocation before any setting data is read.\n\u00a0\n2. **Header count** -- `parseHeaderValueBlock` reads a 32-bit\n`numHeaders` from the decompressed header block and allocates an\n`http.Header` map of that size with no upper bound.\n\u00a0\n3. **Header field size** -- Individual header name and value lengths are\nread as 32-bit integers and used directly as allocation sizes with\nno validation.\n\u00a0\nBecause SPDY header blocks are zlib-compressed, a small on-the-wire\npayload can decompress into attacker-controlled bytes that the parser\ninterprets as 32-bit counts and lengths. A single crafted frame is\nenough to exhaust process memory.\n## Impact\n\u00a0Any program that accepts SPDY connections using spdystream -- directly\nor through a dependent library -- is affected. A remote peer that can\nsend SPDY frames to the service can crash the process with a single\ncrafted SPDY control frame, causing denial of service.\n## Affected versions\n\u00a0`github.com/moby/spdystream` \u003c= v0.5.0\n## Fix\n\u00a0v0.5.1 addresses the receive-side allocation bugs and adds related\nhardening:\n\u00a0\n**Core fixes:**\n\u00a0\n- **SETTINGS entry-count validation** -- The SETTINGS frame reader now\nchecks that `numSettings` is consistent with the declared frame\nlength (`numSettings \u003c= (length-4)/8`) before allocating.\n\u00a0\n- **Header count limit** -- `parseHeaderValueBlock` enforces a maximum\nnumber of headers per frame (default: 1000).\n\u00a0\n- **Header field size limit** -- Individual header name and value\nlengths are checked against a per-field size limit (default: 1 MiB)\nbefore allocation.\n\u00a0\n- **Connection closure on protocol error** -- The connection read loop\nnow closes the underlying `net.Conn` when it encounters an\n`InvalidControlFrame` error, preventing further exploitation on the\nsame connection.\n\u00a0\n**Additional hardening:**\n\u00a0\n- **Write-side bounds checks** -- All frame write methods now verify\nthat payloads fit within the 24-bit length field, preventing the\nlibrary from producing invalid frames.\n\u00a0\n**Configurable limits:**\n\u00a0\n- Callers can adjust the defaults using `NewConnectionWithOptions` or\nthe lower-level `spdy.NewFramerWithOptions` with functional options:\n`WithMaxControlFramePayloadSize`, `WithMaxHeaderFieldSize`, and\n`WithMaxHeaderCount`.\n\u00a0",
"id": "GHSA-pc3f-x583-g7j2",
"modified": "2026-04-16T20:44:01Z",
"published": "2026-04-16T20:44:01Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/moby/spdystream/security/advisories/GHSA-pc3f-x583-g7j2"
},
{
"type": "PACKAGE",
"url": "https://github.com/moby/spdystream"
}
],
"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",
"type": "CVSS_V4"
}
],
"summary": "SpdyStream: DOS on CRI"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.