Skip to content

Security: QuestionHistory grows unbounded between 10s cleanup ticks under a question flood #1723

@bluetoothbot

Description

@bluetoothbot

Problem

QueryHandler.async_response calls self.question_history.add_question_at_time(question, now, known_answers_set) for every non-unicast question in every incoming query the registry can match. QuestionHistory._history is a plain dict[DNSQuestion, (time, known_answers)] with no size cap; the only eviction is async_expire, called from the engine's periodic cleanup at _CACHE_CLEANUP_INTERVAL = 10 seconds. A LAN peer that streams queries with synthetic-but-matching service names — each carrying many distinct questions — can grow _history (and the retained known_answers sets) for up to ~10 s before the next cleanup tick fires, easily reaching hundreds of MB at line-rate.

Why This Matters

Same threat model and same daemon (Home Assistant / IoT bridge) as the _deferred issue; this is a second independent vector that lets a malicious LAN device drive the process toward OOM. The 10 s cleanup interval is long enough for the burst to land before the periodic sweep runs, and add_question_at_time does not consult the size of the dict it's growing.

Suggested Fix

Add a hard cap on _history (e.g. a few thousand entries) and refuse to insert (or evict the oldest by insertion order — dict is ordered) when at cap. Optionally trigger an opportunistic async_expire(now) from inside add_question_at_time when len(self._history) crosses a high-water mark, instead of waiting for the 10 s cleanup timer. Track known_answers as a count or hashed digest if the full set is not needed for the suppression decision.

Details

Severity 🟡 Medium
Category dos
Location src/zeroconf/_history.py:34-77, src/zeroconf/_handlers/query_handler.py:354-356, src/zeroconf/_engine.py:129-144
Effort ⚡ Quick fix

🤖 Created by Kōan from audit session

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions