-
Notifications
You must be signed in to change notification settings - Fork 0
Security and Privacy
This page describes the current implementation, not a security certification. Review provider policies and your local desktop threat model before enabling remote features.
| Feature | Data leaving the machine |
|---|---|
local-cli ASR |
Voice Input itself makes no remote ASR request. It passes a temporary WAV path to /usr/bin/voxtype; that separate backend's behavior depends on its own configuration. |
| Qwen realtime ASR | PCM16 audio chunks, language/session options, and model selection go to the configured Alibaba WebSocket endpoint. |
| Qwen final pass | The complete temporary WAV is embedded as a base64 data:audio/wav request to the configured Alibaba-compatible HTTP endpoint. |
| LLM refinement | Transcript text goes to the configured OpenAI-compatible /chat/completions endpoint. |
| Agent context | Only when enabled, a redacted/capped latest assistant-message excerpt and Pi/Codex label accompany the transcript. |
| Quickshell HUD / output | Local runtime state, Unix socket data, clipboard commands, and input simulation only. |
| Quickshell Settings | Local versioned NDJSON to a dedicated Rust child. Only an explicit Test LLM request contacts the configured LLM endpoint. |
The current source contains no telemetry or analytics client. Network traffic is used by the configured remote ASR and LLM adapters.
With the public default:
[audio]
pre_roll_enabled = falsepw-record starts for a dictation session and is terminated on stop/cancel. When pre-roll is enabled, a resident capture service keeps the microphone stream open for the daemon's lifetime, retaining a short in-memory ring buffer. This reduces clipped first syllables but changes the privacy model and may keep the desktop microphone indicator active.
The complete active-session audio is also retained in memory until final processing finishes. Local and full-audio final recognition use temporary WAV files managed by the operating-system temporary directory; Voice Input does not intentionally archive recordings.
The runtime snapshot contains the live transcript and, after output, may retain:
- raw ASR text;
- refined text;
- refinement status;
- output target/mode/driver;
- the effective recording start timestamp while recording and frozen duration afterward;
- a shortened transcript in the tooltip.
It is written to:
$XDG_RUNTIME_DIR/voice-input/state.json
The waveform publisher sets the runtime directory to mode 0700 and waveform.sock to 0600. Runtime data normally disappears with the user session. A custom state_file creates an additional persistent copy; choose a private path and permissions, or keep auto. voice-input status --format json --extended prints these transcript fields, so sanitize captured command output before sharing it.
Settings QML cannot write configuration. Its Rust child exclusively loads, validates, and serializes the complete supported config. Rust binds each load to an opaque exact-source revision and rejects a save if the file changed after that load. Successful writes use a mode-0700 configuration directory, a mode-0600 file, and temporary-file atomic replacement. This prevents partial files and reduces accidental concurrent overwrites; it does not replace backups.
The standard services declare two optional encrypted credential IDs:
alibaba-api-key
openrouter-api-key
Settings writes encrypted blobs under:
${XDG_CONFIG_HOME:-$HOME/.config}/credstore.encrypted/
Use the Settings UI to avoid putting a literal key in shell history:
voice-input settingsA newly entered key is a password input. QML sends it only through the dedicated child's inherited stdin; Rust then sends it through stdin to systemd-creds encrypt --user --name=<id>. It is never placed in TOML, process arguments, environment variables, logs, or a backend response. Backend responses expose only non-secret credential metadata. The encrypted-store directory is mode 0700; each blob is mode 0600 and is installed by atomic replacement.
Credential operations in this UI are limited to keep and replace. Blank means keep; the UI does not offer deletion. Save and Test LLM clear entered credential fields as soon as the request has been submitted. QML/JavaScript strings are managed values, so clearing references is best effort and cannot guarantee immediate memory zeroization. Test LLM can use the newly entered LLM key without storing it, or use the existing encrypted-store credential.
At service launch, systemd decrypts selected credentials into $CREDENTIALS_DIRECTORY; the daemon reads them from there. Missing credentials are compatible with local-only use. Protecting encrypted blobs still matters; systemd credential security depends on the host and user credential mechanisms available on that system.
The credential named openrouter-api-key is also used for a different OpenAI-compatible api_base_url. The ID is an implementation name, not provider verification.
The daemon resolves each key at startup in this order:
- systemd
$CREDENTIALS_DIRECTORY; -
VOICE_INPUT_ALIBABA_API_KEYorVOICE_INPUT_OPENROUTER_API_KEY; - legacy TOML value accepted from an older configuration.
The public sample has no key fields, and serialization deliberately omits runtime key values. Avoid legacy plaintext TOML and environment variables for the supplied long-running service. Environment variables can be visible through same-user process inspection, diagnostics, or service configuration.
Voice Input binds context to the focused Kitty process and validates PID start time, canonical session root, session identity, file device, and inode. It reads at most 8 MiB from the session tail, chooses only a completed assistant message, removes known secret lines/token patterns, and clamps the outgoing excerpt to 500–12,000 characters.
The LLM prompt marks session text as untrusted and terminology-only. These controls reduce accidental disclosure and prompt injection; heuristic redaction cannot identify every secret, personal detail, proprietary sentence, or novel injection. Keep agent_context_enabled = false for sensitive sessions or untrusted providers. Full details are in Agent Context.
Paste mode temporarily replaces the Wayland or X11 clipboard, sends a paste chord, waits 220 ms, and restores the captured content. During that interval, another same-user clipboard client can observe the transcript. Backup can also be unavailable or restoration can fail, especially for unsupported MIME types or a changing clipboard owner.
clipboard mode intentionally leaves transcript text in the clipboard. Direct type uses wtype and avoids storing the transcript there, but text over 120 characters and default XWayland routing use paste automatically.
Daemon logs include operational metadata such as:
- ASR event/sample counts and first-partial timing;
- LLM attempt type, elapsed milliseconds, coarse outcome, and whether ASR text was retained;
- output target, effective mode, and driver;
- agent type and sanitized excerpt character count.
The timing paths intentionally do not print transcript, agent excerpt, or credentials. Settings also suppresses arbitrary child stderr and never returns credential values. Some propagated backend/provider error messages may originate outside Voice Input; review them before posting.
Privacy-safe diagnostic collection:
journalctl --user -u voice-input.service -b \
| grep -E 'voice-input (realtime ASR|refinement|output|agent context)'Inspect the result manually and remove user names, paths, endpoint details, provider errors, and any unexpected content before sharing.
- Leave pre-roll, remote ASR, final pass, LLM, and agent context disabled until needed.
- Use encrypted systemd credentials and retain
0700config-directory /0600config-file permissions. - Keep the explicit
/usr/bin/voxtypepath and audit that backend separately. - Restrict custom state paths; do not persist state into a synchronized/public directory.
- Treat clipboard managers and same-user processes as able to observe paste payloads.
- Use trusted HTTPS/WSS endpoints and models; endpoint fields are user-controlled.
- Review
journalctland extended status output before attaching them to an issue.
See also: Configuration · Troubleshooting
English Home · 简体中文首页 · Source repository · MIT License
Voice Input is an independent community project. HUD and Settings require Quickshell 0.3+. Review Security and Privacy before enabling remote ASR, LLM refinement, pre-roll, agent context, or replacing credentials in Settings.
Voice Input 是独立的社区项目。HUD 和 Settings 需要 Quickshell 0.3 或更高版本。启用远程 ASR、LLM refinement、pre-roll、Agent 上下文,或者在 Settings 中替换 credential 前,请阅读安全与隐私。