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:]