Description
The DNS stub resolver in subsys/net/lib/dns/resolve.c binds one UDP socket per configured server when the resolver context is initialised (dns_resolve_init_locked() -> register_dispatcher() -> dns_dispatcher_register()), with the local port left at 0 so the stack picks an ephemeral port exactly once. dns_write() then sends every subsequent query from that same socket without re-binding, so the source port is constant for the lifetime of the resolver context while only the 16-bit transaction identifier (ctx->queries[i].id, drawn with sys_rand16_get()) varies per query. RFC 5452 section 9.2 requires both to vary; with a fixed port, an off-path attacker has to guess only the identifier.

The stable port is cheap to learn. Any single observed query reveals it permanently, and it can also be found by probing the ephemeral UDP range: subsys/net/ip/connection.c answers unmatched unicast UDP with an ICMP port-unreachable, so the resolver's socket is the one port in that range that stays silent. Acceptance of a reply is decided solely by get_slot_by_id() matching the transaction identifier and a CRC-16 of the queried name — the reply's source address is never checked (dispatcher_cb() does ARG_UNUSED(addr)), so forged answers need not even be spoofed to appear to come from the configured server; they only need to reach the resolver's port.

An attacker with UDP reachability to the device (same LAN, Wi-Fi or mesh segment, or a globally routable device address) can therefore flood answers for a predictable query name across the 16-bit identifier space during a query window and race the legitimate server. A win makes the application resolve an attacker-chosen address, and with CONFIG_DNS_RESOLVER_CACHE enabled the forged record is retained for its attacker-chosen TTL. The attack still requires winning that race, and applications that validate TLS certificates for the resolved endpoint are largely protected.

The fix draws a fresh local port before each query to a server that has nothing outstanding: dns_randomize_source_port() unregisters the dispatcher, closes and reopens the socket, and re-registers it bound to port 0 so the system selects a new port, raising the per-query guessing space from roughly 16 to roughly 31 bits. Multicast DNS and LLMNR are excluded because their ports are protocol-fixed. The behaviour is controlled by CONFIG_DNS_RESOLVER_RANDOMIZE_SOURCE_PORT (default y).
Published: 2026-10-23
Score: 6.5 Medium
EPSS: n/a
KEV: No
Impact: DNS answer spoofing leading to attacker‑chosen address resolution
Action: Immediate Patch
AI Analysis

Impact

The vulnerability causes the DNS stub resolver in Zephyr to bind a single UDP socket per server during initialization and to keep the local port constant across all subsequent queries. Because only the 16‑bit transaction identifier varies, an attacker who can reach the device over UDP can easily learn the fixed source port and then flood forged responses that match the identifier or the CRC of the queried name. Successful forgery results in the resolver accepting the attacker‑chosen DNS records, which may be cached for the record’s TTL. Although TLS validation mitigates some downstream effects, the ability to redirect name resolution can undermine application integrity and facilitate phishing or protocol hijacking.

Affected Systems

This issue affects devices running Zephyr Project RTOS where the core DNS resolver is enabled. No specific firmware version is listed; the problem exists in all releases that use the unpatched resolver code. Vendors should consult the Zephyr security advisory GHSA‑vwgx-h8w3-xwj7 for the applicable patch.

Risk and Exploitability

The CVSS score of 6.5 indicates moderate to high risk, while the EPSS score is not reported. The vulnerability is not present in CISA’s KEV catalog yet. The attack requires network access to the target device, which can be achieved from the same LAN, Wi‑Fi, or mesh segment, or from any routable address. With the predictable port and the small identifier space, an off‑path attacker can bootstrap solutions by probing the UDP range, then race legitimate responses. While the exploit is feasible, it relies on the attacker being able to send many UDP packets and win a race on the 16‑bit identifier, which mitigates the likelihood compared to a direct remote execution attack. Nonetheless, the risk remains significant for devices exposed to untrusted networks.

Generated by OpenCVE AI on October 23, 2026 at 21:34 UTC.

Remediation

No solution or workaround provided in the CVE record.

OpenCVE Recommended Actions

  • Upgrade Zephyr to a version that includes the resolver randomization fix.
  • Verify that CONFIG_DNS_RESOLVER_RANDOMIZE_SOURCE_PORT is enabled (it defaults to y).
  • If an upgrade is not immediately possible, isolate the device from untrusted networks or restrict UDP traffic to the resolver port using firewall or network segmentation.

Generated by OpenCVE AI on October 23, 2026 at 21:34 UTC.

Tracking

Sign in to view the affected projects.

Advisories

No advisories yet.

History

Fri, 23 Oct 2026 20:15:00 +0000

Type Values Removed Values Added
Description The DNS stub resolver in subsys/net/lib/dns/resolve.c binds one UDP socket per configured server when the resolver context is initialised (dns_resolve_init_locked() -> register_dispatcher() -> dns_dispatcher_register()), with the local port left at 0 so the stack picks an ephemeral port exactly once. dns_write() then sends every subsequent query from that same socket without re-binding, so the source port is constant for the lifetime of the resolver context while only the 16-bit transaction identifier (ctx->queries[i].id, drawn with sys_rand16_get()) varies per query. RFC 5452 section 9.2 requires both to vary; with a fixed port, an off-path attacker has to guess only the identifier. The stable port is cheap to learn. Any single observed query reveals it permanently, and it can also be found by probing the ephemeral UDP range: subsys/net/ip/connection.c answers unmatched unicast UDP with an ICMP port-unreachable, so the resolver's socket is the one port in that range that stays silent. Acceptance of a reply is decided solely by get_slot_by_id() matching the transaction identifier and a CRC-16 of the queried name — the reply's source address is never checked (dispatcher_cb() does ARG_UNUSED(addr)), so forged answers need not even be spoofed to appear to come from the configured server; they only need to reach the resolver's port. An attacker with UDP reachability to the device (same LAN, Wi-Fi or mesh segment, or a globally routable device address) can therefore flood answers for a predictable query name across the 16-bit identifier space during a query window and race the legitimate server. A win makes the application resolve an attacker-chosen address, and with CONFIG_DNS_RESOLVER_CACHE enabled the forged record is retained for its attacker-chosen TTL. The attack still requires winning that race, and applications that validate TLS certificates for the resolved endpoint are largely protected. The fix draws a fresh local port before each query to a server that has nothing outstanding: dns_randomize_source_port() unregisters the dispatcher, closes and reopens the socket, and re-registers it bound to port 0 so the system selects a new port, raising the per-query guessing space from roughly 16 to roughly 31 bits. Multicast DNS and LLMNR are excluded because their ports are protocol-fixed. The behaviour is controlled by CONFIG_DNS_RESOLVER_RANDOMIZE_SOURCE_PORT (default y).
Title DNS resolver reuses a single UDP source port for all queries, easing off-path answer spoofing
Weaknesses CWE-330
References
Metrics cvssV3_1

{'score': 6.5, 'vector': 'CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N'}


Subscriptions

No data.

cve-icon MITRE

Status: PUBLISHED

Assigner: zephyr

Published:

Updated: 2026-10-23T19:56:18.319Z

Reserved: 2026-08-25T16:06:36.387Z

Link: CVE-2026-79981

cve-icon Vulnrichment

No data.

cve-icon NVD

Status : Received

Published: 2026-10-23T20:17:28.040

Modified: 2026-10-23T20:17:28.040

Link: CVE-2026-79981

cve-icon Redhat

No data.

cve-icon OpenCVE Enrichment

Updated: 2026-10-23T21:45:14Z

Weaknesses
  • CWE-330

    Use of Insufficiently Random Values