ZEPHYR · CVE-2026-87045 · Runtime
FIX → 4.5.0 +1 ✓ verified
The Zephyr HTTP/2 server clears its stream binding on every frame, so a stray CONTINUATION frame with no preceding HEADERS makes a 404/405 response or a dynamic POST/PUT/PATCH write through a NULL pointer. An unauthenticated remote peer can fault and halt the device; the advisory states no confidentiality or integrity impact.
first public Nov 6, 2026 · 2 sources
Check it with your coding agent
It checks your repository and tells you if you’re affected, with the fix.
Applications built on Zephyr that enable the built-in HTTP server (CONFIG_HTTP_SERVER) with HTTP/2 are exposed, including cleartext h2c connections, since TLS does not prevent the attack. Applications built without CONFIG_HTTP_SERVER are not affected. Any peer that can reach the server can trigger it without credentials or prior state.
Not affected if default-config, http-server-disabled, no-http-server, no-http2
Who cares embedded, http2, iot, unauthenticated, zephyr
The HTTP/2 server in subsys/net/lib/http/http_server_http2.c clears the connection's stream binding at the start of every frame. handle_http_frame_header() executed client->current_stream = NULL unconditionally, but a CONTINUATION frame does not open a new stream and enter_http_frame_continuation_state() never re-bound one, so the rest of the header block was processed with client->current_stream unset. Two paths then write through the NULL pointer. A request for an unregistered resource, or a method the matched resource does not support, is answered by send_http2_404() or send_http2_405(), and both call send_headers_frame(), which unconditionally sets client->current_stream->headers_sent = true. A POST, PUT or PATCH to a registered dynamic resource reaches handle_http2_dynamic_resource(), which unlike its siblings (handle_http2_static_resource(), dynamic_get_del_opts_req_v2(), dynamic_post_put_req_v2()) had no client->current_stream == NULL guard, and stores through the pointer with client->current_stream->current_detail = dynamic_detail.
Any peer that can reach the server can trigger this without authentication or prior state. A single stray CONTINUATION frame with END_HEADERS set, sent right after the client preface and requesting any unregistered path, is enough, because nothing rejected a CONTINUATION that no HEADERS frame had opened. A legitimate split header block (a HEADERS frame with END_HEADERS clear whose payload ends on a header-field boundary, then a CONTINUATION with END_HEADERS set) reaches the same state. The in-tree test test_http2_post_headers_with_continuation() did not catch this because it splits the header block mid field, which takes the handle_incomplete_http_header() shortcut that keeps the stream bound.
The result is a write to a fixed low address (a small offset into struct http2_stream_ctx), which faults on mainstream targets (flash/vector-table region on Cortex-M, or a trap under MPU/MMU null-pointer detection), and the default fatal-error handler halts the system. Impact is an unauthenticated, remotely triggerable denial of service against any device running the HTTP/2 server: the 404 path needs no particular resource to be registered, and HTTP/2 is built into CONFIG_HTTP_SERVER with cleartext h2c accepted, so TLS does not prevent it. Neither the target address nor the written value is attacker-controlled, so there is no confidentiality or integrity impact. Applications built without CONFIG_HTTP_SERVER are not affected.
Are you affected?
Tell InfraStack what you run. It checks this one, and every next one, against your stack.
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
Upgrade to 4.5.0 +1
4.3.2 (4.1-4.3 line) or 4.5.0 (4.4 line); fix commit e72a9d9498092bfbb7feed4b479bf21bc3218c3dThis page as .md · .json · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.