🛡️ Sentinel: Bound wyoming payload_length to prevent DoS
Co-authored-by: mARTin-B78 <91568406+mARTin-B78@users.noreply.github.com>
This commit is contained in:
parent
b8fde76d7e
commit
7415a560dc
@ -112,6 +112,11 @@ class WakewordListener:
|
|||||||
self._handle_detection()
|
self._handle_detection()
|
||||||
|
|
||||||
payload_len = msg.get("payload_length", 0)
|
payload_len = msg.get("payload_length", 0)
|
||||||
|
|
||||||
|
if not isinstance(payload_len, int) or payload_len < 0 or payload_len > 1048576:
|
||||||
|
logbuffer.log(f"[wakeword] Invalid payload_length: {payload_len}")
|
||||||
|
break
|
||||||
|
|
||||||
if payload_len > 0:
|
if payload_len > 0:
|
||||||
# Consume payload
|
# Consume payload
|
||||||
remaining = payload_len
|
remaining = payload_len
|
||||||
|
|||||||
@ -322,6 +322,13 @@ def _drain_detections(buf: bytes) -> tuple[bytes, int]:
|
|||||||
except (ValueError, UnicodeDecodeError):
|
except (ValueError, UnicodeDecodeError):
|
||||||
return rest, found
|
return rest, found
|
||||||
plen = msg.get("payload_length", 0) or 0
|
plen = msg.get("payload_length", 0) or 0
|
||||||
|
if not isinstance(plen, int):
|
||||||
|
raise ValueError(f"Invalid payload_length type: {type(plen)}")
|
||||||
|
if plen < 0:
|
||||||
|
raise ValueError(f"Negative payload_length: {plen}")
|
||||||
|
if plen > 1048576: # 1MB limit to prevent DoS via unbounded reads
|
||||||
|
raise ValueError(f"Unreasonably large payload_length: {plen}")
|
||||||
|
|
||||||
if len(rest) < plen:
|
if len(rest) < plen:
|
||||||
return buf, found # payload not fully arrived yet; wait for more
|
return buf, found # payload not fully arrived yet; wait for more
|
||||||
rest = rest[plen:]
|
rest = rest[plen:]
|
||||||
|
|||||||
23
linux/tests/test_wakeword_security.py
Normal file
23
linux/tests/test_wakeword_security.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from blitztext.wakeword_bench import _drain_detections
|
||||||
|
|
||||||
|
def test_drain_detections_payload_length_validation():
|
||||||
|
# Test massive payload length
|
||||||
|
msg = {"type": "info", "payload_length": 1048577}
|
||||||
|
buf = json.dumps(msg).encode("utf-8") + b"\n"
|
||||||
|
with pytest.raises(ValueError, match="Unreasonably large payload_length"):
|
||||||
|
_drain_detections(buf)
|
||||||
|
|
||||||
|
# Test negative payload length
|
||||||
|
msg = {"type": "info", "payload_length": -1}
|
||||||
|
buf = json.dumps(msg).encode("utf-8") + b"\n"
|
||||||
|
with pytest.raises(ValueError, match="Negative payload_length"):
|
||||||
|
_drain_detections(buf)
|
||||||
|
|
||||||
|
# Test invalid type for payload length
|
||||||
|
msg = {"type": "info", "payload_length": "invalid"}
|
||||||
|
buf = json.dumps(msg).encode("utf-8") + b"\n"
|
||||||
|
with pytest.raises(ValueError, match="Invalid payload_length type"):
|
||||||
|
_drain_detections(buf)
|
||||||
Loading…
Reference in New Issue
Block a user