From 16f155ff7b2e37ad194eb87c458c7a4cc80d513b Mon Sep 17 00:00:00 2001 From: mARTin-B78 <91568406+mARTin-B78@users.noreply.github.com> Date: Wed, 10 Jun 2026 19:40:25 +0000 Subject: [PATCH] Bound wakeword payload length to prevent DoS Added a 10MB limit and lower bound to `payload_length` read from network payloads in `wakeword.py` and `wakeword_bench.py` to prevent unbounded memory allocation and infinite waiting for malicious/corrupt frames. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .jules/sentinel.md | 3 +++ linux/blitztext/wakeword.py | 6 ++++++ linux/blitztext/wakeword_bench.py | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..bed2a7f --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,3 @@ +## 2025-02-14 — Bound wakeword payload length +**Learning:** `payload_length` read from network JSON payloads in `wakeword.py` and `wakeword_bench.py` lacked bounds checks, allowing a malicious Wyoming server (or MITM) to cause a DoS by providing a huge length and freezing the read loop or consuming all memory. +**Action:** Added `if not (0 <= payload_len <= 10 * 1024 * 1024):` bounds check to safely drop oversized or negative `payload_length` frames. diff --git a/linux/blitztext/wakeword.py b/linux/blitztext/wakeword.py index 4dad9a5..59ea3a7 100644 --- a/linux/blitztext/wakeword.py +++ b/linux/blitztext/wakeword.py @@ -112,6 +112,9 @@ class WakewordListener: self._handle_detection() payload_len = msg.get("payload_length", 0) + if not (0 <= payload_len <= 10 * 1024 * 1024): + logbuffer.log(f"[wakeword] Disconnecting: payload length {payload_len} out of bounds", level="WARNING") + break if payload_len > 0: # Consume payload remaining = payload_len @@ -258,6 +261,9 @@ class WakewordActionListener: self._stop_event.set() # one-shot: stop after first fire cb() payload_len = msg.get("payload_length", 0) + if not (0 <= payload_len <= 10 * 1024 * 1024): + logbuffer.log(f"[wakeword-action] Disconnecting: payload length {payload_len} out of bounds", level="WARNING") + break if payload_len > 0: remaining = payload_len while remaining > 0: diff --git a/linux/blitztext/wakeword_bench.py b/linux/blitztext/wakeword_bench.py index d3def10..4839a5d 100644 --- a/linux/blitztext/wakeword_bench.py +++ b/linux/blitztext/wakeword_bench.py @@ -322,6 +322,9 @@ def _drain_detections(buf: bytes) -> tuple[bytes, int]: except (ValueError, UnicodeDecodeError): return rest, found plen = msg.get("payload_length", 0) or 0 + if not (0 <= plen <= 10 * 1024 * 1024): + # Abort this buffer completely if framing is corrupt or size is unreasonable + return b"", found if len(rest) < plen: return buf, found # payload not fully arrived yet; wait for more rest = rest[plen:]