CVE-2026-28810 Overview
CVE-2026-28810 is a DNS Cache Poisoning vulnerability affecting the Erlang/OTP kernel's built-in DNS resolver (inet_res and inet_db modules). The vulnerability stems from the generation of predictable numbers or identifiers (CWE-340), where the resolver uses a sequential, process-global 16-bit transaction ID for UDP queries without implementing source port randomization.
Response validation relies almost entirely on this predictable transaction ID, making DNS cache poisoning practical for an attacker who can observe one query or predict the next ID. This design conflicts with RFC 5452 recommendations for mitigating forged DNS answers. While inet_res is intended for use in trusted network environments with trusted recursive resolvers, earlier documentation did not clearly state this deployment assumption, potentially leading users to deploy the resolver in environments where spoofed DNS responses are possible.
Critical Impact
Attackers who can observe DNS queries or predict transaction IDs can poison the DNS cache, redirecting traffic to malicious servers and enabling man-in-the-middle attacks, credential theft, or malware distribution.
Affected Products
- Erlang/OTP versions from OTP 17.0 until OTP 28.4.2, 27.3.4.10, and 26.2.5.19
- Erlang/OTP kernel versions from 3.0 until 10.6.2, 10.2.7.4, and 9.2.4.11
- Applications using inet_res module (lib/kernel/src/inet_res.erl)
- Applications using inet_db module (lib/kernel/src/inet_db.erl)
Discovery Timeline
- 2026-04-07 - CVE-2026-28810 published to NVD
- 2026-04-07 - Last updated in NVD database
Technical Details for CVE-2026-28810
Vulnerability Analysis
The vulnerability exists in the Erlang/OTP kernel's DNS resolution implementation within inet_res.erl and inet_db.erl. The core issue is the use of a sequential, process-global 16-bit transaction ID for UDP DNS queries. With only 65,536 possible values and predictable sequencing, an attacker can feasibly guess the correct transaction ID for a DNS response.
Additionally, the resolver does not implement source port randomization, which is a critical defense-in-depth measure recommended by RFC 5452. Without randomized source ports, attackers only need to predict the transaction ID rather than both the port and ID combination, dramatically reducing the entropy an attacker must overcome.
The vulnerability allows attackers to inject forged DNS responses that will be accepted and cached by the resolver, enabling DNS cache poisoning attacks.
Root Cause
The root cause is insufficient entropy in DNS query validation mechanisms. The inet_res module relies on a predictable 16-bit sequential transaction ID without source port randomization. This design decision conflicts with RFC 5452 security recommendations and makes the resolver vulnerable to cache poisoning in untrusted network environments.
The affected program files are:
- lib/kernel/src/inet_db.erl
- lib/kernel/src/inet_res.erl
Attack Vector
The attack is network-based and requires the attacker to either observe DNS queries to determine the current transaction ID sequence or blindly predict the next ID. An attacker positioned to intercept or inject network traffic can:
- Observe an outgoing DNS query to identify the current transaction ID
- Calculate the expected transaction ID for subsequent queries
- Send a forged DNS response with the predicted transaction ID before the legitimate response arrives
- The resolver accepts the malicious response and caches the poisoned entry
The security patches address the port binding mechanism in gen_udp.erl and inet.erl:
-doc(#{equiv => open(Port, [])}).
-spec open(Port) -> {ok, Socket} | {error, Reason} when
- Port :: inet:port_number() | -1,
+ Port :: inet:port_number(),
Socket :: socket(),
Reason :: system_limit | inet:posix().
Source: GitHub Commit Update
The patch removes the special -1 port value handling, which was associated with the insecure port assignment mechanism:
{ip6_address() | 'any' | 'loopback',
port_number()}} |
undefined, % Internal - no bind()
- BPort :: port_number() | -1,
+ BPort :: port_number(),
Opts :: [socket_setopt()],
Protocol :: socket_protocol() | 'mptcp',
Family :: address_family(),
Source: GitHub Commit Update
Detection Methods for CVE-2026-28810
Indicators of Compromise
- Unexpected DNS responses arriving from IP addresses that are not configured DNS servers
- DNS responses with transaction IDs that appear to be sequentially predictable
- Multiple DNS responses received for single queries (indicating race conditions between legitimate and spoofed responses)
- Unusual changes in resolved IP addresses for critical domains
Detection Strategies
- Monitor for anomalous DNS traffic patterns, particularly responses from unexpected source IP addresses
- Implement network-level logging to detect DNS response injection attempts
- Analyze DNS transaction ID patterns for sequential or predictable sequences
- Deploy DNSSEC validation where possible to detect forged responses
Monitoring Recommendations
- Enable verbose logging on DNS resolution activities in Erlang/OTP applications
- Implement network intrusion detection rules to identify DNS spoofing attempts
- Monitor for sudden changes in cached DNS records, particularly for critical infrastructure domains
- Establish baseline DNS traffic patterns and alert on deviations
How to Mitigate CVE-2026-28810
Immediate Actions Required
- Upgrade Erlang/OTP to patched versions: OTP 28.4.2, 27.3.4.10, or 26.2.5.19 or later
- Review deployment environments to ensure inet_res is only used in trusted network segments
- Consider using external DNS resolution mechanisms until patches can be applied
- Implement network segmentation to limit exposure of systems using vulnerable Erlang/OTP versions
Patch Information
Security patches are available through the official Erlang/OTP repository. The fixes have been committed to address the predictable transaction ID and port randomization issues:
Detailed information is available in the GitHub Security Advisory.
Workarounds
- Deploy inet_res only in trusted network environments with trusted recursive resolvers as originally intended
- Use a local caching DNS resolver (such as unbound or dnsmasq) with DNSSEC validation instead of inet_res
- Implement network-level protections such as egress filtering and DNS response validation at firewall level
- Consider using TCP for DNS queries where supported to reduce spoofing risk
# Example: Configure application to use system DNS resolver instead of inet_res
# In your Erlang application configuration (sys.config)
[
{kernel, [
{inet_dns_resolve, []} % Use OS resolver instead of inet_res
]}
].
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

