Advisories for Pypi/Zeroconf package

2026

zeroconf: Unbounded exception-dedup state retains packet buffers via traceback frame locals, enabling LAN-local memory exhaustion

DNSIncoming._log_exception_debug and the four QuietLogger exception-dedup methods stored an unbounded _seen_logs dict keyed by str(sys.exc_info()[1]). The seven IncomingDecodeError messages raised from _read_name / _decode_labels_at_offset (RFC 6762 §18 name-decoding error paths) all embed self.source — the peer's ephemeral source port, varying per packet — plus byte offset and pointer link, so every attacker-influenced combination produced a fresh dedup key. The stored value was the full sys.exc_info() triple, whose traceback's frame locals …

zeroconf has unbounded recursion in DNS compression-pointer decoder that allows LAN-local denial of service

DNSIncoming._decode_labels_at_offset recurses once per DNS-name compression pointer (RFC 1035 §4.1.4). Pointer cycles and label counts were capped, but the chain length of unique forward pointers was not. A single ~3 kB mDNS packet carrying ~1500 chained pointers drives the recursion past CPython's default limit, and RecursionError was not listed in DECODE_EXCEPTIONS, so it escaped DNSIncoming.init and was logged by asyncio's default exception handler. Any unauthenticated host on the local link …

zeroconf has unbounded DNS record cache that allows LAN-local memory exhaustion via multicast flood

DNSCache._async_add inserted every response record into cache, _expirations, _expire_heap, and service_cache with no cap on entry count. The only pre-existing protection was a PTR TTL floor (_DNS_PTR_MIN_TTL = 1125 s, RFC 6762 §10), which actually prolonged attacker-injected records, and a periodic async_expire on _CACHE_CLEANUP_INTERVAL = 10 s that could not keep up with a flood. Any unauthenticated host on the local link (UDP/5353, 224.0.0.251 / ff02::fb) can multicast valid mDNS …