Skip to content
← Help

Security & Threat Model

Last updated: July 7, 2026

Every claim below is sourced from Daisy's code — you can read it yourself at github.com/smallbricktory/daisy-local. File references are given throughout so any of this can be re-audited.

Daisy is a local-first meeting recorder, transcriber, and summarizer. The security posture follows from that: your recordings, transcripts, and summaries live on your disk, in open formats, and leave your machine only through paths you explicitly configure. Credentials are encrypted at rest. The app is fully functional offline.

1. Architecture and trust boundaries

Daisy's local-first architecture. Your machine holds the Daisy app — a WebView UI with strict CSP and no network access, and a Rust core where all egress happens — plus your profile directory, with an encrypted vault for secrets and plaintext meeting files. MCP and local AI are loopback only. Only TLS calls you configure leave the machine: license and update checks to daisy.smbr.app, optional cloud transcription/LLM under your own key, model downloads from Hugging Face, and your own webhook and calendar URLs.

Trust boundaries:

  1. WebView ↔ Rust core. The UI cannot reach the network or the filesystem directly; every operation goes through Tauri commands. CSP: connect-src ipc: http://ipc.localhost only — even injected script in the WebView has no network path (tauri.conf.json).
  2. App ↔ disk. Secrets cross this boundary only inside the encrypted vault envelope. Meeting content crosses it in plaintext by design (§3).
  3. Machine ↔ network. Nothing containing meeting content crosses this boundary unless you configure a cloud provider or a webhook integration (§4).

2. Data classification

Class Examples At rest Rationale
Credentials Provider API keys, webhook auth secrets, calendar feed URLs, per-install signing seed, MCP token, voiceprint embeddings Encrypted (vault) Dangerous in motion; encryption must travel with the file (backups, sync)
Meeting content Audio, transcripts, summaries, chapters, in-call chat, search index Plaintext, open formats Your data; grep-able, sync-able, outlives the app. Protect with full-disk encryption (§7)
Configuration Settings, tags, prompts, workflows, contacts Plaintext Needed before vault unlock; contains no secrets
License / install identity Install ID, license key, signed validity stamp Plaintext Needed before vault unlock; low-value, seat-limited, server-revocable

3. Data at rest

All paths are relative to the profile directory (your platform's data dir).

Encrypted — the vault. keys.vault.json holds provider API keys, integration webhook auth values, subscribed calendar feed URLs, the per-install signing seed, the MCP bearer token, and voiceprint embeddings. calendar/events.json is an encrypted cache derived from those feed URLs.

The vault uses AES-256-GCM with a key derived by Argon2id (64 MiB, 3 iterations, 4 lanes), a fresh random salt and nonce on every write. A wrong passphrase is an authentication failure, never garbage output.

  • Passphrase mode (default): minimum 22 characters and a "strong" strength score, enforced at creation. There is no recovery — a lost passphrase means re-entering your keys, never lost recordings.
  • Machine mode (opt-in): the key derives from the OS machine ID and the vault auto-unlocks at startup. This protects vault copies that leave the machine (backups, synced folders) but not against someone with access to the running machine. Choose passphrase mode if your threat model includes other local users.

Plaintext — meeting content lives under sessions/<id>/: audio, transcript, summary, chapters, in-call chat, and the local semantic-search index. This is your data in open formats — see Vault & profile.

Plaintext — configuration (settings, tags, prompts, workflows, contacts, integration history) contains no secrets; it's needed before the vault unlocks.

Logs are local only, rotated daily, deleted after 7 days. Transcript and summary text is never written to logs; window names are salted-hashed.

Telemetry: none. No analytics, crash reporters, or tracking calls exist anywhere in the app.

4. What leaves your machine, and when

Offline, Daisy records, transcribes (local Whisper), summarizes (local LLM), and searches with zero egress. This is the complete inventory.

Automatic — never any meeting content

Call Destination Carries Gate
Update check daisy.smbr.app/updates/… A version string On launch + every 6 h, only if the auto-update-check setting is on; notify-only (the app never downloads or installs updates itself); fail-silent
License check-in daisy.smbr.app/api/license/refresh License key, install ID On launch + a 6 h beat; throttled to ~1/day server-side; fail-silent
Calendar refresh Your ICS/webcal URLs The fetch itself Only if you subscribed a calendar

User-configured or user-clicked — content only by your choice

Feature Destination Carries
Cloud summaries / chat / analysis Anthropic, or any OpenAI-compatible endpoint (incl. local LM Studio / Ollama) Transcript text + your prompts (your key)
License activate / deactivate daisy.smbr.app/api/activate License key, install ID
Webhook integrations Your URL (Zapier / n8n / your endpoint) The payloads you select per destination — see Integrations
Model download huggingface.co Nothing personal (you click download)
Help / source links www.daisylocal.app, the source repo Nothing — opens in your browser

Daisy Cloud — the daisy.smbr.app/api/gateway/… endpoint in the code is an internal-only service tied to the license key. When a license is entitled, Daisy proxies the AI step (transcript text, never audio) to Anthropic and OpenAI using our own keys — Ed25519-signed per install, with no stealable API key. It's an internal convenience, not part of a normal install; regular users bring a local model or their own key.

Every remote call uses TLS. The only plaintext HTTP in the app is loopback (your local AI servers, the MCP server). The UI performs zero direct HTTP — every call above happens in the Rust core behind an explicit command, and the CSP gives injected WebView script no network path.

5. Threat model

Assumptions. Your OS and user account are not compromised (Daisy is an app, not an anti-malware boundary — software running as you can read what you can read). TLS/PKI works.

Threat Scenario Mitigation
Information disclosure Profile folder leaves the machine (cloud backup, Syncthing, sold laptop, support zip) Credentials stay AES-256-GCM ciphertext wherever the files travel; meeting content is plaintext by design — see §6
Information disclosure Another local user reads the vault file Passphrase mode: Argon2id makes offline guessing expensive; a strength policy blocks weak passphrases
Information disclosure Data leaks into diagnostics No telemetry; logs carry no transcript text; window names hashed
Spoofing Stolen "API key" for the gateway No bearer credential exists — a per-install Ed25519 signature over method, path, timestamp, nonce, and body hash; replay-limited
Tampering Malicious "update" Updater is notify-only; you download from the website in your browser. Windows builds are Authenticode-signed, macOS builds Developer ID-signed (both to Apexis Solutions Inc.)
Tampering License forgery Validity stamps are Ed25519-signed by the vendor, verified against a key pinned in the binary
Elevation of privilege Web content escapes the UI Strict CSP (no network, frames, or objects); zero direct HTTP from the frontend; all privileged ops are explicit commands
Elevation of privilege A local process abuses the MCP port Loopback bind + vault-held bearer token; off by default; write access separately gated

Explicitly out of scope: a compromised OS or root-level malware / memory scraping of the running, unlocked app (no desktop app can defend this); machine- mode vault against a local attacker (a documented tradeoff); a configured cloud provider's own data handling (their retention applies to what you send them — the local default sends nothing); physical theft of a powered-on, logged-in machine.

6. Residual risks

  1. Meeting content is plaintext on disk. Deliberate: encrypting it would let a lost passphrase destroy your entire history, complicate crash recovery, and break grep/sync of your own data — while adding little against the realistic attacker (anything running as you reads it anyway while the app is open). The mitigation is full-disk encryption (§7), which covers the real at-rest threat: a stolen or discarded disk.
  2. The vault protects copies, not the running machine. An attacker with persistent code execution as you can wait for unlock.
  3. Model downloads are not checksum-pinned. Integrity rests on TLS and the host.
  4. Webhooks trust your endpoint. Payloads go to the URL you configure.

7. What you should do

  • Turn on full-disk encryption — BitLocker (Windows), FileVault (macOS), LUKS (Linux). This is the intended protection for meeting content at rest.
  • Prefer passphrase mode for the vault on shared or managed machines.
  • Treat the profile folder like the recordings it contains when backing up or syncing — the vault file is safe anywhere; transcripts are as private as the folder you put them in.
  • Point webhooks only at endpoints you control or trust.

Running Daisy where PHI is involved? See Configuring Daisy for HIPAA and PHI.

8. Reporting a vulnerability

Please report suspected vulnerabilities privately by email to support@daisylocal.app rather than in a public issue. Include steps to reproduce and the build SHA from Settings → About. We aim to acknowledge within 72 hours.