CVE-2026-48487 Overview
CVE-2026-48487 affects the python-zeroconf library, a pure Python implementation of multicast DNS (mDNS) service discovery. The vulnerability resides in _read_character_string and _read_string within src/zeroconf/_protocol/incoming.py. These functions advance self.offset by an attacker-declared RDLENGTH without validating it against self._data_len. Unauthenticated hosts on the local link can send crafted TXT, HINFO, or A/AAAA records over UDP port 5353 (224.0.0.251 or ff02::fb) with rdlength=65535. The result is truncated, attacker-shaped entries seeded into DNSCache and ServiceInfo.properties. The issue is fixed in version 0.149.16 and is classified under [CWE-130] Improper Handling of Length Parameter Inconsistency.
Critical Impact
Local-link attackers can poison the Zeroconf record cache and inject shaped values into ServiceInfo.properties, corrupting downstream service discovery decisions.
Affected Products
- python-zeroconf versions prior to 0.149.16
- Applications embedding Zeroconf for mDNS/DNS-SD service discovery
- IoT and smart-home integrations that rely on Zeroconf record parsing
Discovery Timeline
- 2026-07-17 - CVE-2026-48487 published to NVD
- 2026-07-23 - Last updated in NVD database
Technical Details for CVE-2026-48487
Vulnerability Analysis
Zeroconf parses incoming mDNS packets by reading resource records whose payload length is declared in the RDLENGTH field. The parser uses _read_character_string for TXT and HINFO records and _read_string for raw byte blobs, including address data. Neither function verified that self.offset + length stayed within self._data_len before advancing the cursor. Python slice semantics silently truncate reads that run past the buffer, so the decoded value appears valid while the offset is corrupted. Subsequent records in the same packet are then parsed from an out-of-bounds position, and the truncated, attacker-shaped payload is stored in DNSCache and ServiceInfo.properties. Because mDNS traffic is unauthenticated and multicast, any host on the same broadcast domain can supply these records.
Root Cause
The root cause is missing length validation against the packet buffer size. The parser trusted the wire-declared RDLENGTH up to 65535 bytes without cross-checking it against the actual UDP payload length.
Attack Vector
An attacker sharing the local link sends a crafted mDNS response to 224.0.0.251:5353 or ff02::fb containing a TXT, HINFO, or A/AAAA record with an inflated rdlength. The victim caches truncated key/value pairs or address bytes, influencing later service resolution.
"""Reads a character string from the packet"""
length = self.view[self.offset]
self.offset += 1
+ # Python slicing silently truncates when indices exceed the buffer,
+ # but self.offset still advances by the declared length below; without
+ # this check a record with an inflated character-string length would
+ # land in the cache carrying a payload shorter than the wire claimed
+ # and leave the parser pointed past _data_len for the next record.
+ if self.offset + length > self._data_len:
+ raise IncomingDecodeError(
+ f"Character string length {length} at offset {self.offset} overruns "
+ f"packet of {self._data_len} bytes from {self.source}"
+ )
info = self.data[self.offset : self.offset + length].decode("utf-8", "replace")
self.offset += length
return info
def _read_string(self, length: _int) -> bytes:
"""Reads a string of a given length from the packet"""
+ if self.offset + length > self._data_len:
+ raise IncomingDecodeError(
+ f"String length {length} at offset {self.offset} overruns "
+ f"packet of {self._data_len} bytes from {self.source}"
+ )
info = self.data[self.offset : self.offset + length]
self.offset += length
return info
Source: GitHub Commit 544449596e645fcaad3834fa0cb614a54f847a82 — the patch raises IncomingDecodeError when the declared length would overrun the packet.
Detection Methods for CVE-2026-48487
Indicators of Compromise
- Inbound mDNS packets on UDP/5353 with resource records declaring rdlength=65535 or values larger than the remaining UDP payload.
- Unexpected TXT, HINFO, or A/AAAA entries appearing in application ServiceInfo.properties from unfamiliar service instance names.
- Repeated malformed mDNS responses targeting 224.0.0.251 or ff02::fb from a single link-local source.
Detection Strategies
- Deploy an mDNS-aware packet inspection rule that flags records where the declared RDLENGTH exceeds the remaining UDP payload length.
- Monitor python-zeroconf application logs for IncomingDecodeError messages referencing character string or string length overruns once the patch is applied.
- Inventory Python environments with pip list or SBOM tooling to identify installations of zeroconf below 0.149.16.
Monitoring Recommendations
- Baseline expected mDNS talkers on each broadcast domain and alert on new sources sending large RDLENGTH values.
- Capture full mDNS packet traces from IoT and OT segments to support offline forensic review of suspected cache poisoning.
- Correlate service discovery anomalies with host-level authentication or connection failures that could indicate spoofed endpoints.
How to Mitigate CVE-2026-48487
Immediate Actions Required
- Upgrade python-zeroconf to version 0.149.16 or later across all Python environments and container images.
- Rebuild and redeploy any packaged applications, appliances, or firmware that vendor the vulnerable Zeroconf library.
- Restart long-running Python services after upgrade so the patched parser handles new mDNS traffic.
Patch Information
The fix is available in python-zeroconf 0.149.16. See the GitHub Release Notes for 0.149.16, the GitHub Security Advisory GHSA-qc2x-6f54-m6h9, and the upstream Pull Request Discussion for background on the length validation added to _read_character_string and _read_string.
Workarounds
- Segment untrusted devices onto isolated VLANs so they cannot reach hosts running Zeroconf listeners on UDP/5353.
- Block or rate-limit mDNS traffic at the network edge where service discovery is not required for business function.
- Disable Zeroconf service listeners in applications where mDNS discovery is not a functional requirement.
# Upgrade to the patched version
pip install --upgrade 'zeroconf>=0.149.16'
# Verify installed version
python -c "import zeroconf; print(zeroconf.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

