-
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 controls, and model selection go to the configured Alibaba WebSocket endpoint. |
| Qwen Audio3 Streaming | PCM16 audio chunks, streaming controls, configured vocabulary, and the optional start-time session terminology view go to the selected Audio3 WebSocket endpoint. |
| Qwen Audio3 Native | The complete WAV, optional language hints, and configured vocabulary go to the selected Audio3 Native endpoint. The request is capped at 10 MiB. Start-time session terminology is not added to Native requests. |
| Qwen final pass | The complete temporary WAV is embedded as a base64 data:audio/wav request to the configured Alibaba-compatible HTTP endpoint. |
| Audio3 session terminology view | At recording start, Voice Input freezes eligible terminology from the focused Kitty Pi/Codex session. Redaction, Jieba segmentation, deduplication, frequency ranking, and capping are local. Audio3 receives only the resulting newline-delimited terms, at most 400 characters including newlines, in run-task. |
| Refinement terminology view | If LLM refinement is enabled, the same frozen snapshot is independently capped at 96 terms and 1,500 characters and accompanies the transcript. Stop-time focus contributes only destination style and whether Agent Markdown is requested. |
| LLM refinement | Transcript text, the optional refinement terminology view, and the destination style/Agent Markdown instruction go to the configured OpenAI-compatible /chat/completions endpoint. |
| Quickshell HUD / output | Local runtime state, Unix socket frames, 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 configured remote ASR and LLM adapters.
The original assistant message, term frequencies, session paths, and window/desktop metadata are not sent as terminology. High-confidence ASCII case/separator variants are normalized locally before Refine, and the model output is normalized again locally afterward. See Agent Context for the complete lifecycle and limits.
Refinement prompts define the model as a transcript editor, not an assistant. They explicitly require it to edit only the transcript and to preserve questions, requests, and commands as dictated text—never answer, execute, discuss, or act on them. Agent Markdown changes formatting, not this boundary.
Session terminology is marked as untrusted vocabulary-only data. It must not be treated as instructions, facts, claims, or authority. This reduces prompt-injection risk but cannot make an external model or provider trustworthy.
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 and retains 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 retained in memory until final processing finishes. Local, final-pass, and Audio3 Native recognition use temporary WAV files in the operating-system temporary directory; Voice Input does not intentionally archive recordings.
The runtime snapshot contains live transcript data and may retain raw/refined text, refinement state, output target metadata, timing, and a shortened tooltip transcript after output. The default location is:
$XDG_RUNTIME_DIR/voice-input/state.json
The standard runtime directory is mode 0700; state files, temporary state files, and runtime sockets/files that carry private data use mode 0600. Runtime data normally disappears with the user session. A custom state_file can create a persistent copy outside that protected directory; secure its parent and file yourself, or keep auto.
For support, the preferred artifact is schema 4 diagnostics:
voice-input diagnostics
voice-input diagnostics --format text
voice-input diagnostics --format jsonDiagnostics uses a strict allowlist. It reports safe configuration choices, coarse runtime/session state, stage and failure categories, bounded identifiers, counts, durations, delay/timestamp aggregates, reconnect totals, Native-mode decisions, and selected-result latency. It does not contain transcripts, endpoint/host values, model names, credentials or keys, terminology, provider messages, session paths, window/app metadata, or Agent source content. A provider error identifier may appear only as a short sanitized ASCII token, never as the provider's message.
Do not share output from voice-input status; in particular, never share voice-input status --format json --extended. Extended status contains transcript fields. Do not attach state.json, waveform data, Pi/Codex JSONL, raw audio, or an unreviewed journal. Prefer diagnostics and still review it before posting.
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 stores 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 a 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 there. Missing credentials are compatible with local-only use. Protecting encrypted blobs still matters; systemd credential security depends on host and user credential mechanisms.
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; - a 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 tooling, or service configuration.
Agent context is a start-time immutable terminology snapshot. Voice Input validates the focused Kitty Pi/Codex process, session identity, canonical paths, PID start time, and file identity before reading at most 8 MiB from the session tail and selecting the latest completed assistant source. It performs secret-pattern redaction and terminology extraction locally.
These checks reduce accidental disclosure; heuristic redaction cannot identify every secret, personal detail, proprietary term, or novel injection. Keep agent_context_enabled = false for sensitive sessions or untrusted providers. Cancellation prevents later output and work where possible, but it cannot revoke data that was already read locally or sent after recording started.
All output uses clipboard paste. On Wayland, both the temporary transcript clipboard and restored clipboard payload are marked sensitive. Clipboard backup skips the sensitive metadata MIME x-kde-passwordManagerHint and captures only a selected non-sensitive-metadata MIME payload.
This protection is effective only with compatible Wayland clipboard managers. X11/XWayland has no equivalent sensitive-metadata guarantee. During the replacement interval, another same-user clipboard client can observe the transcript. Ownership changes, unsupported MIME types, or helper failure can also prevent complete restoration.
Clipboard backup uses a private temporary file. It is removed after successful restoration, but a crash or forced termination can leave a sensitive backup residue in the temporary directory. Treat the temporary directory and crash artifacts accordingly.
Output helpers and the local ASR backend run with explicit deadlines and output-size caps. Simultaneous stdout/stderr is drained without waiting on one stream first, and timeout cleanup terminates the helper process group. User-facing errors are sanitized and do not include captured clipboard content, transcript text, provider stderr, or unbounded child output.
These controls limit hangs, memory growth, and accidental content propagation; they do not make an untrusted executable safe. Keep configured executable paths explicit and audit /usr/bin/voxtype, clipboard tools, compositor tools, and any custom command separately.
- Leave pre-roll, remote ASR, final pass, LLM, and Agent context disabled until needed.
- Use encrypted systemd credentials and retain
0700directory /0600file permissions. - Keep the explicit
/usr/bin/voxtypepath and audit that backend separately. - Restrict custom state paths; do not persist state into a synchronized or public directory.
- Treat clipboard managers, temporary backup files, and same-user processes as able to observe paste payloads.
- Use trusted HTTPS/WSS endpoints and models; endpoint fields are user-controlled.
- Collect
voice-input diagnostics --format jsonfor support. Never share status/extended output, state files, or an unreviewed journal.
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 前,请阅读安全与隐私。