Every CVE Search/ Get API key

CVE-2026-83813

Twisted: DNS Response Spoofing in twisted.names Due to Missing Source Address Validation

3.1 LowFix available

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Attack profile

How easy it is to exploit

Attack vector
Adjacent network
Complexity
High
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
Low
Availability
None

Exploit likelihood

0.11%Unchanged since Oct 24, 2026
90%50%10%1%

What each source reports

CVE List Score used 3.1

Twisted: DNS Response Spoofing in twisted.names Due to Missing Source Address Validation

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Record
CVE-2026-83813
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
EUVDEUVD-2026-109152 3.1

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Record
EUVD-2026-109152
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-jj36-9pvh-vj5r 3.1

Twisted: DNS Response Spoofing in twisted.names Due to Missing Source Address Validation

Summary

twisted.names.dns.DNSDatagramProtocol, the UDP transport used by twisted's DNS client (twisted.names.client.Resolver, createResolver, and anything built on it, including MX lookups in twisted.mail), accepts a DNS response for a pending query solely on the basis of the 16-bit transaction ID matching. It never checks that the response actually originated from the server the query was sent to. Any host that can deliver a UDP packet to the resolver's listening port with the correct transaction ID can inject a forged answer, independent of the real server's address. This is a materially weaker defense than standard DNS resolver practice (transaction ID plus source-address validation, typically also source-port rotation), and enables off-path DNS response spoofing / cache poisoning.

Details

DNSDatagramProtocol.datagramReceived (src/twisted/names/dns.py, line 3350) is:

def datagramReceived(self, data, addr):
    """
    Read a datagram, extract the message in it and trigger the associated
    Deferred.
    """
    m = Message()
    try:
        m.fromStr(data)
    except EOFError:
        ...
    except ValueError as ex:
        ...
    except BaseException:
        ...

    if m.id in self.liveMessages:
        d, canceller = self.liveMessages[m.id]
        del self.liveMessages[m.id]
        canceller.cancel()
        try:
            d.callback(m)
        except BaseException:
            log.err()
    else:
        if m.id not in self.resends:
            self.controller.messageReceived(m, self, addr)

The addr parameter, the UDP source address of the datagram, is accepted but never compared against the address the corresponding query was sent to. The only check is m.id in self.liveMessages, and liveMessages is keyed purely by the transaction ID chosen in DNSMixin.pickID(). The listening socket is a plain listenUDP(0, self, maxPacketSize=512) (line 3348), not connected to the queried server, so the kernel does not filter by source address either; any host can deliver a UDP datagram to this socket.

The transaction ID itself is generated with secureRandom (randomSource(), line 174), so it is not predictable, but at 16 bits it is a 1-in-65536 space per attempt. twisted.names.client.Resolver, the standard, documented DNS client, mitigates brute-force guessing of that space by creating a brand-new DNSDatagramProtocol bound to a fresh, independently random source port (_connectedProtocol(), src/twisted/names/client.py line 206, using dns.randomSource()) for every individual query, and tearing the socket down once the query completes (_query(), line 253). This gives an off-path attacker roughly 32 bits of combined entropy (port and transaction ID) to guess per query issued through the standard client, not just the 16 bits of the transaction ID alone.

The missing source-address check is still a real gap for two reasons. First, it removes a defense-in-depth backstop that DNS resolver best practice (RFC 5452) treats as independent from port and ID randomization; an attacker who is on-path, shares a broadcast domain or NAT with the resolver or the real DNS server, or is otherwise able to observe or narrow the ephemeral port faces no additional barrier at all, since source-address validation is exactly the check that would stop them. Second, DNSDatagramProtocol is itself a public, documented class; code that constructs one directly and issues more than one query against the same instance, rather than going through client.Resolver's per-query protocol and port cycling, reuses the same source port for every query after the first, so guessing the 16-bit transaction ID alone is sufficient from that point on.

twisted.names.client.Resolver uses this same DNSDatagramProtocol class for every UDP query it issues, so every consumer of the standard twisted DNS client, including twisted.mail's MX resolution, is subject to the same unauthenticated accept logic in…

Record
GHSA-jj36-9pvh-vj5r
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
NVD 3.1

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Record
CVE-2026-83813
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
OSV 3.1

Twisted: DNS Response Spoofing in twisted.names Due to Missing Source Address Validation

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Record
CVE-2026-83813
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
OSVDEBIAN-CVE-2026-83813 3.1

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Record
DEBIAN-CVE-2026-83813
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02
Show 5 moreShow less
OSVGHSA-jj36-9pvh-vj5r 3.1

Twisted: DNS Response Spoofing in twisted.names Due to Missing Source Address Validation

Summary

twisted.names.dns.DNSDatagramProtocol, the UDP transport used by twisted's DNS client (twisted.names.client.Resolver, createResolver, and anything built on it, including MX lookups in twisted.mail), accepts a DNS response for a pending query solely on the basis of the 16-bit transaction ID matching. It never checks that the response actually originated from the server the query was sent to. Any host that can deliver a UDP packet to the resolver's listening port with the correct transaction ID can inject a forged answer, independent of the real server's address. This is a materially weaker defense than standard DNS resolver practice (transaction ID plus source-address validation, typically also source-port rotation), and enables off-path DNS response spoofing / cache poisoning.

Details

DNSDatagramProtocol.datagramReceived (src/twisted/names/dns.py, line 3350) is:

def datagramReceived(self, data, addr):
    """
    Read a datagram, extract the message in it and trigger the associated
    Deferred.
    """
    m = Message()
    try:
        m.fromStr(data)
    except EOFError:
        ...
    except ValueError as ex:
        ...
    except BaseException:
        ...

    if m.id in self.liveMessages:
        d, canceller = self.liveMessages[m.id]
        del self.liveMessages[m.id]
        canceller.cancel()
        try:
            d.callback(m)
        except BaseException:
            log.err()
    else:
        if m.id not in self.resends:
            self.controller.messageReceived(m, self, addr)

The addr parameter, the UDP source address of the datagram, is accepted but never compared against the address the corresponding query was sent to. The only check is m.id in self.liveMessages, and liveMessages is keyed purely by the transaction ID chosen in DNSMixin.pickID(). The listening socket is a plain listenUDP(0, self, maxPacketSize=512) (line 3348), not connected to the queried server, so the kernel does not filter by source address either; any host can deliver a UDP datagram to this socket.

The transaction ID itself is generated with secureRandom (randomSource(), line 174), so it is not predictable, but at 16 bits it is a 1-in-65536 space per attempt. twisted.names.client.Resolver, the standard, documented DNS client, mitigates brute-force guessing of that space by creating a brand-new DNSDatagramProtocol bound to a fresh, independently random source port (_connectedProtocol(), src/twisted/names/client.py line 206, using dns.randomSource()) for every individual query, and tearing the socket down once the query completes (_query(), line 253). This gives an off-path attacker roughly 32 bits of combined entropy (port and transaction ID) to guess per query issued through the standard client, not just the 16 bits of the transaction ID alone.

The missing source-address check is still a real gap for two reasons. First, it removes a defense-in-depth backstop that DNS resolver best practice (RFC 5452) treats as independent from port and ID randomization; an attacker who is on-path, shares a broadcast domain or NAT with the resolver or the real DNS server, or is otherwise able to observe or narrow the ephemeral port faces no additional barrier at all, since source-address validation is exactly the check that would stop them. Second, DNSDatagramProtocol is itself a public, documented class; code that constructs one directly and issues more than one query against the same instance, rather than going through client.Resolver's per-query protocol and port cycling, reuses the same source port for every query after the first, so guessing the 16-bit transaction ID alone is sufficient from that point on.

twisted.names.client.Resolver uses this same DNSDatagramProtocol class for every UDP query it issues, so every consumer of the standard twisted DNS client, including twisted.mail's MX resolution, is subject to the same unauthenticated accept logic in…

Record
GHSA-jj36-9pvh-vj5r
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
OSVUBUNTU-CVE-2026-83813 3.1

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Record
UBUNTU-CVE-2026-83813
CVSS 3.1
3.1 LowCVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-05
OSVAZL-111419 No score

CVE-2026-83813 affecting package python-twisted 22.10.0-7

Twisted is an event-based framework for internet applications, supporting Python 3.6+. Prior to 26.10.0rc1, twisted.names.dns.DNSDatagramProtocol accepts a UDP DNS response for a pending query when its 16-bit transaction ID matches but does not verify that the response came from the queried host and port. An attacker able to deliver a packet to the resolver's listening port with the correct transaction ID can inject a forged answer. The standard twisted.names.client.Resolver uses a new random source port for each query, increasing off-path attack complexity, while applications that reuse a DNSDatagramProtocol instance expose only the transaction-ID search space after the first query. A successful forgery can redirect hostname resolution and enable mail interception, server-side request forgery, or man-in-the-middle positioning. This issue is fixed in version 26.10.0rc1.

Record
AZL-111419
Updated
2026-11-05
OSVCLSA-2026-1793702577 No score

TuxCare security update for twisted (1 CVE)

TuxCare rebuilt twisted to address 1 CVE. Fixed in 20.3.0.post8+tuxcare.

Record
CLSA-2026-1793702577
Updated
2026-11-03
OSVopenSUSE-SU-2026:12381-1 No score

python-Twisted-doc-26.10.0-1.1 on GA media

These are all security issues fixed in the python-Twisted-doc-26.10.0-1.1 package on the GA media of openSUSE Tumbleweed.

Record
openSUSE-SU-2026:12381-1
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
twisted
PyPI
through 26.4.0
26.10.0rc1
python-twisted
Azure Linux:3
through 22.10.0-7 None known
twisted
TuxCare:PyPI
20.3.0 up to 20.3.0.post8+tuxcare, plus listed versions
20.3.0.post4+tuxcare20.3.0.post5+tuxcare20.3.0.post6+tuxcare20.3.0.post7+tuxcare
20.3.0.post8+tuxcare
twisted
Debian:12
All versions, plus listed versions
22.4.0-422.4.0-4+deb12u123.10.0-123.10.0-224.10.0-1
Show 20 moreShow less
24.10.0-224.11.0-124.3.0-124.3.0-224.3.0-324.7.0-124.7.0-224.7.0-325.5.0-125.5.0-225.5.0-325.5.0-425.5.0-526.10.0-126.4.0-126.4.0-226.4.0-326.4.0-426.4.0-526.4.0-6
None known
twisted
Debian:13
All versions, plus listed versions
24.11.0-125.5.0-125.5.0-225.5.0-325.5.0-4
Show 8 moreShow less
25.5.0-526.10.0-126.4.0-126.4.0-226.4.0-326.4.0-426.4.0-526.4.0-6
None known
twisted
Debian:14
before 26.10.0-1, plus listed versions
24.11.0-125.5.0-125.5.0-225.5.0-325.5.0-4
Show 7 moreShow less
25.5.0-526.4.0-126.4.0-226.4.0-326.4.0-426.4.0-526.4.0-6
26.10.0-1
twisted
PyPI
before 26.10.0rc1, plus listed versions
1.0.11.0.31.0.41.0.51.0.6
Show 45 moreShow less
1.0.71.1.01.1.11.2.010.0.010.1.010.2.011.0.011.1.012.0.012.1.012.2.012.3.013.0.013.1.013.2.014.0.014.0.114.0.215.0.015.1.015.2.015.2.115.3.015.4.015.5.016.0.016.1.016.1.116.2.016.3.016.3.116.3.216.4.016.4.116.5.016.5.0rc116.5.0rc216.6.016.6.0rc116.7.0rc116.7.0rc217.1.017.1.0rc117.5.0
26.10.0rc1
twisted
Ubuntu:Pro:14.04:LTS
All versions, plus listed versions
13.0.0-1ubuntu113.2.0-1ubuntu113.2.0-1ubuntu1.213.2.0-1ubuntu1.2+esm113.2.0-1ubuntu1.2+esm213.2.0-1ubuntu1.2+esm3
None known
twisted
Ubuntu:Pro:16.04:LTS
All versions, plus listed versions
15.2.1-1ubuntu215.5.0-115.5.0-215.5.0-2ubuntu115.5.0-4
Show 9 moreShow less
16.0.0~pre1-116.0.0~pre1-1ubuntu116.0.0~pre1-2ubuntu116.0.0~pre1-316.0.0-116.0.0-1ubuntu0.216.0.0-1ubuntu0.416.0.0-1ubuntu0.4+esm116.0.0-1ubuntu0.4+esm2
None known
twisted
Ubuntu:Pro:18.04:LTS
All versions, plus listed versions
16.6.0-2ubuntu317.9.0-117.9.0-217.9.0-2ubuntu0.117.9.0-2ubuntu0.317.9.0-2ubuntu0.3+esm117.9.0-2ubuntu0.3+esm2
None known
Show 6 moreShow less
Affected packages
PackageAffectedFixed
twisted
Ubuntu:20.04:LTS
All versions, plus listed versions
18.9.0-3ubuntu118.9.0-518.9.0-618.9.0-6build118.9.0-6ubuntu1
Show 7 moreShow less
18.9.0-818.9.0-1118.9.0-11ubuntu0.20.04.118.9.0-11ubuntu0.20.04.218.9.0-11ubuntu0.20.04.318.9.0-11ubuntu0.20.04.418.9.0-11ubuntu0.20.04.5
None known
twisted
Ubuntu:22.04:LTS
All versions, plus listed versions
20.3.0-7ubuntu120.3.0-7ubuntu322.1.0-2ubuntu222.1.0-2ubuntu2.122.1.0-2ubuntu2.3
Show 5 moreShow less
22.1.0-2ubuntu2.422.1.0-2ubuntu2.522.1.0-2ubuntu2.622.1.0-2ubuntu2.722.1.0-2ubuntu2.8
None known
twisted
Ubuntu:24.04:LTS
All versions, plus listed versions
22.4.0-422.4.0-4ubuntu123.10.0-224.3.0-124.3.0-1ubuntu0.124.3.0-1ubuntu0.224.3.0-1ubuntu0.3
None known
twisted
Ubuntu:26.10
All versions, plus listed versions
25.5.0-526.4.0-426.4.0-4ubuntu0.1
None known
twisted
Ubuntu:26.04:LTS
All versions, plus listed versions
24.11.0-125.5.0-425.5.0-525.5.0-5ubuntu0.125.5.0-5ubuntu0.2
None known
python-Twisted
openSUSE:Tumbleweed
From an advisory covering 4 CVEs
before 26.10.0-1.1
26.10.0-1.1

History

History
RecordedChangedSources
affected
affectedOSV
affected, factsOSV
affected, aliasesOSV
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-83813 is a low vulnerability (CVSS 3.1) in Twisted, published October 23, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.11%, the 1st percentile. Fixed in twisted 26.10.0rc1.

References

Show 9 moreShow less
This page doesn't list everything

Left out here: 61 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open