Cap buffered audio and keep transcripts out of INFO logs

Wyoming has no authentication, so buffered audio is attacker-controlled.
self.audio grew until AudioStop with no bound: measured at ~11 MB/s over
loopback, one connection exhausts 32 GB in under an hour, and a stuck
satellite that never sends AudioStop does the same by accident. Cap it at
--max-audio-seconds (default 120), dropping the excess with a single warning
while still transcribing what was captured. Verified: a client streaming
10.8 GB now moves server RSS by 213 MB rather than 10.8 GB.

Transcripts were logged at INFO. Log files are long-lived and world-readable
under /tmp on macOS, so every voice command sat in plaintext readable by any
local account. INFO now records duration, latency and character count; the
text moved behind --debug.

Both are covered by mutation-checked tests, and the README gains a Security
section covering the unauthenticated trust boundary, the 0.0.0.0 bind that
also exposes VPN interfaces, and running the daemon as a non-admin user.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 03:44:25 +01:00
co-authored by Claude Opus 5
parent 9bf887e780
commit 5a6fc62106
4 changed files with 170 additions and 9 deletions
+12 -2
View File
@@ -8,7 +8,7 @@ from wyoming.info import AsrModel, AsrProgram, Attribution, Info
from wyoming.server import AsyncServer
from .engine import ParakeetEngine
from .handler import ParakeetEventHandler
from .handler import DEFAULT_MAX_AUDIO_SECONDS, ParakeetEventHandler
_LOGGER = logging.getLogger(__name__)
__version__ = "1.0.0"
@@ -25,7 +25,17 @@ def build_parser() -> argparse.ArgumentParser:
parser.add_argument("--uri", required=True, help="unix:// or tcp://")
parser.add_argument("--model", default=DEFAULT_MODEL, help="HuggingFace model id")
parser.add_argument("--language", default="en", help="Language code reported to HA")
parser.add_argument("--debug", action="store_true", help="Log DEBUG messages")
parser.add_argument(
"--max-audio-seconds",
type=float,
default=DEFAULT_MAX_AUDIO_SECONDS,
help="Cap on buffered audio per utterance (default: %(default)s)",
)
parser.add_argument(
"--debug",
action="store_true",
help="Log DEBUG messages, including transcript text",
)
parser.add_argument("--log-format", default=logging.BASIC_FORMAT)
parser.add_argument("--version", action="version", version=__version__)
return parser