v1.0.0 — First stable release
First stable public release. All five development phases complete: MVP → hardening
→ structured output → ergonomics → security. 7 MCP tools, 33 tests, fully local.
Security
- Resolve-before-validate in
transcribe(). Path symlinks are now fully resolved
before extension and allow-list checks, closing a TOCTOU race where a symlink could
change between validation and CLI invocation. - Null-byte rejection. Paths containing
\x00are rejected immediately in
transcribe()before any filesystem access. - Model identifier sanitization. The
modelparameter is now validated against
[a-zA-Z0-9_:.-]+before being passed to the CLI, preventing argument injection. - No allow-list leakage in errors. "Access denied" messages no longer include the
full allow-list; this was an information-disclosure issue. start_watch()folder validation. The folder path is now checked against the
allow-list before starting the watcher; previously any directory could be watched.- Symlink rejection in watcher.
FolderWatcher._scan()skips symbolic links;
a symlink insideincoming/pointing outside the allow-list could otherwise cause
MacWhisper to read arbitrary files. MACWHISPER_LOG_PATHmust be under$HOME.Config.from_env()rejects log
paths outside the user's home directory to prevent log-file hijacking.- Output size cap.
transcribe()raisesTranscribeErrorifmwstdout exceeds
10 MB, guarding against runaway output consuming memory.