GHSA-G586-CCQF-7X4R
Vulnerability from github – Published: 2026-07-09 23:19 – Updated: 2026-07-09 23:19Summary
Mint's HTTP/2 client accepts PUSH_PROMISE frames from any server it connects to and inserts every promised stream into a per-connection map without consulting max_concurrent_streams. A malicious or compromised HTTP/2 server can flood the client with PUSH_PROMISE frames and withhold the matching response HEADERS, pinning one map entry per frame indefinitely until the client process runs out of memory.
Details
'Elixir.Mint.HTTP2':handle_push_promise/3 in lib/mint/http2.ex dispatches every inbound PUSH_PROMISE frame to 'Elixir.Mint.HTTP2':decode_push_promise_headers_and_add_response/5, which inserts a :reserved_remote entry into conn.streams for the promised ID. The only validation applied is that the promised ID is even and not already present; client_settings.max_concurrent_streams is not consulted at promise time.
The concurrency cap is only checked when the response HEADERS for the promised stream arrive. A server that emits PUSH_PROMISE frames and never sends the matching HEADERS never trips that check, and the existing tally counts only streams in open states, not :reserved_remote entries.
HTTP/2 server push is accepted by default (client_settings.enable_push defaults to true), so no application opt-in is required. A single long-lived HTTP/2 connection to a hostile server lets it pin one conn.streams entry per PUSH_PROMISE frame, with no upper bound.
PoC
- Stand up a raw TCP HTTP/2 server that completes the handshake and ACKs the client's
SETTINGS. - Wait for the client's request
HEADERSand capture its odd stream ID. - Send a flood of
PUSH_PROMISEframes (flags = END_HEADERS) associated with the captured stream, each promising a fresh even stream ID and carrying a minimal HPACK-encoded header block. - Never send the matching response
HEADERSfor any of the promised IDs. - The client's
conn.streamsmap grows by one entry perPUSH_PROMISEframe (~148 bytes/entry); memory grows linearly and the BEAM process eventually crashes with OOM.
Impact
Remote, unauthenticated denial-of-service against any process using Mint as an HTTP/2 client against an untrusted or attacker-influenced server. Server push is on by default, so no application code change can prevent it short of disabling push or upgrading. Affected populations include outbound HTTP/2 clients in web backends, webhook delivery systems, scrapers, federated and proxy components, and any service that follows redirects to third-party HTTP/2 origins.
Workarounds
Disable HTTP/2 server push on connections to untrusted servers by passing client_settings: [enable_push: false] to 'Elixir.Mint.HTTP':connect/4. Mint will then reject any inbound PUSH_PROMISE frame with a PROTOCOL_ERROR before the vulnerable code path is reached.
Resources
- Introduction commit: https://github.com/elixir-mint/mint/commit/65c6394d05a1b8aa4a7461708c3aa173e8d7a5cf
- Patch commit: https://github.com/elixir-mint/mint/commit/70b97b6a5209fb288b0e04d8e657dda26c59de67
{
"affected": [
{
"package": {
"ecosystem": "Hex",
"name": "mint"
},
"ranges": [
{
"events": [
{
"introduced": "0.2.0"
},
{
"fixed": "1.9.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-48862"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-09T23:19:29Z",
"nvd_published_at": "2026-06-02T16:16:44Z",
"severity": "HIGH"
},
"details": "### Summary\n\nMint\u0027s HTTP/2 client accepts `PUSH_PROMISE` frames from any server it connects to and inserts every promised stream into a per-connection map without consulting `max_concurrent_streams`. A malicious or compromised HTTP/2 server can flood the client with `PUSH_PROMISE` frames and withhold the matching response `HEADERS`, pinning one map entry per frame indefinitely until the client process runs out of memory.\n\n### Details\n\n`\u0027Elixir.Mint.HTTP2\u0027:handle_push_promise/3` in `lib/mint/http2.ex` dispatches every inbound `PUSH_PROMISE` frame to `\u0027Elixir.Mint.HTTP2\u0027:decode_push_promise_headers_and_add_response/5`, which inserts a `:reserved_remote` entry into `conn.streams` for the promised ID. The only validation applied is that the promised ID is even and not already present; `client_settings.max_concurrent_streams` is not consulted at promise time.\n\nThe concurrency cap is only checked when the response `HEADERS` for the promised stream arrive. A server that emits `PUSH_PROMISE` frames and never sends the matching `HEADERS` never trips that check, and the existing tally counts only streams in open states, not `:reserved_remote` entries.\n\nHTTP/2 server push is accepted by default (`client_settings.enable_push` defaults to `true`), so no application opt-in is required. A single long-lived HTTP/2 connection to a hostile server lets it pin one `conn.streams` entry per `PUSH_PROMISE` frame, with no upper bound.\n\n### PoC\n\n1. Stand up a raw TCP HTTP/2 server that completes the handshake and ACKs the client\u0027s `SETTINGS`.\n2. Wait for the client\u0027s request `HEADERS` and capture its odd stream ID.\n3. Send a flood of `PUSH_PROMISE` frames (`flags = END_HEADERS`) associated with the captured stream, each promising a fresh even stream ID and carrying a minimal HPACK-encoded header block.\n4. Never send the matching response `HEADERS` for any of the promised IDs.\n5. The client\u0027s `conn.streams` map grows by one entry per `PUSH_PROMISE` frame (~148 bytes/entry); memory grows linearly and the BEAM process eventually crashes with OOM.\n\n### Impact\n\nRemote, unauthenticated denial-of-service against any process using Mint as an HTTP/2 client against an untrusted or attacker-influenced server. Server push is on by default, so no application code change can prevent it short of disabling push or upgrading. Affected populations include outbound HTTP/2 clients in web backends, webhook delivery systems, scrapers, federated and proxy components, and any service that follows redirects to third-party HTTP/2 origins.\n\n## Workarounds\n\nDisable HTTP/2 server push on connections to untrusted servers by passing `client_settings: [enable_push: false]` to `\u0027Elixir.Mint.HTTP\u0027:connect/4`. Mint will then reject any inbound `PUSH_PROMISE` frame with a `PROTOCOL_ERROR` before the vulnerable code path is reached.\n\n## Resources\n\n* Introduction commit: https://github.com/elixir-mint/mint/commit/65c6394d05a1b8aa4a7461708c3aa173e8d7a5cf\n* Patch commit: https://github.com/elixir-mint/mint/commit/70b97b6a5209fb288b0e04d8e657dda26c59de67",
"id": "GHSA-g586-ccqf-7x4r",
"modified": "2026-07-09T23:19:29Z",
"published": "2026-07-09T23:19:29Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/elixir-mint/mint/security/advisories/GHSA-g586-ccqf-7x4r"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-48862"
},
{
"type": "WEB",
"url": "https://github.com/elixir-mint/mint/commit/70b97b6a5209fb288b0e04d8e657dda26c59de67"
},
{
"type": "WEB",
"url": "https://cna.erlef.org/cves/CVE-2026-48862.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/elixir-mint/mint"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/EEF-CVE-2026-48862"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "mint: Unbounded streams map growth via PUSH_PROMISE without follow-up HEADERS"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
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.