CVE-2026-43972 Overview
CVE-2026-43972 is an Origin Validation Error [CWE-346] in the gun_http2 module of the ninenines gun Erlang HTTP client. The library fails to verify that an incoming HTTP/2 PUSH_PROMISE frame references a resource the connected server is authoritative for. A malicious or compromised HTTP/2 server can plant cookies scoped to arbitrary third-party domains into the client's shared cookie store. This enables session fixation and, when planted cookies override legitimate session tokens, account takeover against unrelated origins. The flaw affects gun versions 2.0.0 through 2.3.x and is fixed in 2.4.0.
Critical Impact
Any application using gun for HTTP/2 requests can have cookies for arbitrary domains injected into its shared cookie jar after a single request to an attacker-controlled server.
Affected Products
- ninenines gun >= 2.0.0
- ninenines gun < 2.4.0
- Erlang applications using gun_http2 with gun_cookies enabled
Discovery Timeline
- 2026-06-08 - CVE-2026-43972 published to NVD
- 2026-06-09 - Last updated in NVD database
Technical Details for CVE-2026-43972
Vulnerability Analysis
The vulnerability resides in how gun handles server-initiated HTTP/2 server push. In gun_http2:push_promise_frame/7, the :authority pseudo-header from an incoming PUSH_PROMISE frame is stored verbatim into the promised stream record. The client never validates that the promised authority matches the origin of the underlying connection.
When gun_http2:headers_frame/9 later processes the response headers for that promised stream, it calls gun_cookies:set_cookie_header/7 using the unvalidated server-supplied authority. Cookie storage occurs before any status-code branching and before user code can intervene. As a result, Set-Cookie headers returned in the pushed response are stored against the attacker-chosen domain in gun's shared cookie store.
This behavior violates RFC 7540 §10.6 and RFC 9113 §8.4, which require receivers to treat as a protocol error any push for a resource the server is not authoritative for.
Root Cause
The root cause is missing origin validation on the :authority pseudo-header during PUSH_PROMISE processing. The original code destructured the promised authority directly into local bindings used for cookie storage, with no comparison against the connection's negotiated scheme and authority.
Attack Vector
An attacker controlling an HTTP/2 server that a victim client connects to over a normal request can return a PUSH_PROMISE frame whose :authority points to any third-party domain. The pushed response can carry arbitrary Set-Cookie headers. No user interaction beyond the initial HTTP/2 request is required. The planted cookies enable session fixation, and if they overwrite a legitimate session identifier, account takeover against the targeted domain.
push_promise_frame(State=#http2_state{socket=Socket, transport=Transport,
status=Status, http2_machine=HTTP2Machine0},
StreamID, PromisedStreamID, Headers, #{
- method := Method, scheme := Scheme,
- authority := Authority, path := Path},
+ method := PromisedMethod, scheme := PromisedScheme,
+ authority := PromisedAuthority, path := PromisedPath},
EvHandler, EvHandlerState0) ->
- #stream{ref=StreamRef, reply_to=ReplyTo, flow=InitialFlow} = get_stream_by_id(State, StreamID),
+ #stream{
+ ref=StreamRef,
+ authority=Authority,
+ reply_to=ReplyTo,
+ flow=InitialFlow
+ } = get_stream_by_id(State, StreamID),
+ Scheme = scheme(State),
+ %% We cancel the push_promise immediately when we are shutting
+ %% down or when the scheme/authority doesn't match the request's.
+ OKOrError = case Status of
+ connected ->
+ case {Scheme, iolist_to_binary(Authority)} of
+ {PromisedScheme, PromisedAuthority} -> ok;
+ _ -> protocol_error
+ end;
+ _ ->
+ cancel
+ end,
PromisedStreamRef = make_ref(),
Source: GitHub commit 567863ff in ninenines/gun. The patch retrieves the original request's Authority from the parent stream record, compares it against PromisedScheme and PromisedAuthority, and emits protocol_error on mismatch — aborting the push before cookies are stored.
Detection Methods for CVE-2026-43972
Indicators of Compromise
- Unexpected entries in the gun cookie jar scoped to domains the application never directly requested.
- HTTP/2 PUSH_PROMISE frames received on outbound client connections whose :authority does not equal the origin server's host.
- Session anomalies — users authenticating with session identifiers that did not originate from the legitimate identity provider.
- Outbound HTTP/2 connections to untrusted endpoints immediately followed by inbound Set-Cookie activity against unrelated domains.
Detection Strategies
- Inventory all Erlang/OTP services and resolve the gun dependency version; flag any release in the range >= 2.0.0, < 2.4.0.
- Instrument gun callers to log promised stream :authority values and alert when they diverge from the connection's authority.
- Apply network-layer inspection on outbound HTTP/2 traffic to flag PUSH_PROMISE frames carrying cross-origin authorities.
Monitoring Recommendations
- Audit the persisted cookie store used by gun clients for entries with domains outside the application's expected request graph.
- Correlate authentication backend logs with session identifiers seen client-side to detect fixation attempts.
- Track dependency manifests (rebar.lock, mix.lock) in CI to alert on reintroduction of vulnerable gun versions.
How to Mitigate CVE-2026-43972
Immediate Actions Required
- Upgrade gun to version 2.4.0 or later in all dependent applications and rebuild release artifacts.
- Purge any persisted gun cookie stores that may contain attacker-planted entries from prior connections.
- Audit recent outbound HTTP/2 destinations and revoke any sessions whose identifiers may have been fixated.
Patch Information
The fix is committed as 567863ff53802fed21c3b3f25812db7f7ae29676 in the ninenines/gun repository and released in gun 2.4.0. The patch records the connection's authority on the parent stream and rejects PUSH_PROMISE frames whose :authority and scheme do not match — returning protocol_error per RFC 9113 §8.4. See the CNA advisory for CVE-2026-43972 and the OSV entry EEF-CVE-2026-43972.
Workarounds
- Disable HTTP/2 server push in gun client options where the API permits, forcing rejection of PUSH_PROMISE frames.
- Disable the gun cookie store (cookie_store option) for connections that do not require cookie handling, eliminating the storage sink.
- Restrict gun usage to a curated set of trusted HTTP/2 endpoints until the upgrade to 2.4.0 is deployed.
# rebar.config — pin gun to the patched release
{deps, [
{gun, "2.4.0"}
]}.
# mix.exs — Elixir projects consuming gun
defp deps do
[
{:gun, "~> 2.4.0"}
]
end
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

