Snug's security claims are meant to be falsifiable. The two load-bearing ones:
- C1 — Token boundary. Credentials never enter an app iframe, never reach the LLM, and never reach an app publisher. In the current architecture every secret lives in
snug_secretsinside the user's own SQLite file — stripped from hub-bound sync pushes and default exports (and VACUUMed so deleted values don't linger in free pages). A personal sync origin you explicitly connect (e.g. your own Dropbox) carries the full file, secrets included — that is how credentials travel between your own devices (ADR-0014). - C2 — Sandbox integrity. App iframes run
sandbox="allow-scripts"only (neverallow-same-origin), withconnect-src 'none'for app-originated traffic and a fixed CDN allowlist. LLM calls originate from the host page only — an app has no network of its own.
Anything that makes either claim false is a critical finding, and we want to hear it.
Preferred: GitHub private vulnerability reporting. Also fine: security@snugprotocol.org.
Please include a reproduction — a Playground sequence, a single-file app HTML, or a failing test is ideal. Please don't open public issues for suspected vulnerabilities.
- Acknowledgment within 3 business days.
- Initial assessment (in scope? severity?) within 14 days.
- Confirmed C1/C2 breaks jump the queue ahead of all feature work; we ask for coordinated disclosure of up to 90 days, and will usually ship much faster.
- No bug bounty. Credit in release notes and the repository's security acknowledgments unless you prefer anonymity.
In scope
- Escaping or weakening the iframe sandbox (C2): executing with same-origin privileges, reaching the network from app code, loading from outside the CDN allowlist.
- Breaking the token boundary (C1): extracting anything from
snug_secretsinto an app, an envelope payload, an LLM prompt, a hub-bound sync push, or a default export. - Envelope-boundary validation gaps in
packages/protocol/packages/runner(frames that bypass zod validation, smuggle capabilities, or confuse the bridge). - The reference server (
apps/server):/invoke, session/CSRF handling,/userdbcompare-and-swap endpoints, artifact cache. - Prompt-injection with a boundary consequence — LLM output or app content that causes the host to violate C1/C2. (Prompt injection that merely makes the LLM say something silly inside its existing permissions is a quality issue, not a security one.)
- The credential-handling layer (
packages/authand thesnug_connectionsstorage inpackages/db): defeating the per-app host-allowlist freeze, the OAuth flow binding, or the credential store's custody rules. The connected-fetch injection/scrubbing runtime has shipped and is fully in scope — its ten gates, the frozen host ceiling, the mutating-call confirm, and the response/error scrubbing are the highest-value targets in the repo. - The desktop shell (
apps/desktop): the Tauri IPC boundary, the per-command capability gates, and the local WhatsApp helper (apps/whatsapp-sidecar) it supervises. Note the platform caveat below — Windows is a known break and does not ship. - Design-level flaws in the protocol itself — report here or against
snugprotocol/spec; same address either way.
Out of scope
- Vulnerabilities in LLM providers, browsers, or OS/WebView internals (report upstream; we'll mitigate where we can).
- A user deliberately exporting with secrets included or pasting their own key into an unrelated malicious site.
- Secrets present in a personal sync origin you connected — that is by design (ADR-0014; see the token-boundary claim above).
- Denial of service against your own browser tab or your own self-hosted server.
- Infrastructure misconfiguration of third-party self-hosted deployments.
- Social engineering of the maintainer, and anything requiring an already-compromised machine.
The full written threat model is docs/threat-model.md: scope, assets, adversaries, trust boundaries, the enforced invariants with the file that enforces each and the test that would fail if it regressed — and, with equal prominence, the residuals that are accepted and not mitigated. If you are deciding whether to trust this system, read its §6 before its §5.
The desktop shell ships macOS only — through alpha, beta and 1.0 — and the reason is a security one. On Windows, wry's WebView2 backend discards for_main_frame_only, so Tauri's IPC invoke key is injected into sandbox="allow-scripts" app iframes — a C1 and C2 break that any installed app could exploit, with no off-switch available at the wry, Tauri, or WebView2 layer. macOS is unaffected (WKWebView honors the flag). No Windows build has ever been distributed and none will ship in this configuration. Windows desktop is reconsidered post-1.0, as its own decision — if you need it, that is the honest timeline rather than "soon". Details: threat model R-5, ADR-0021 D8's addendum, and the root-cause note.
The browser Playground is unaffected by the above and runs everywhere.
We consider good-faith security research under this policy authorized, and will not pursue or support legal action for it. Good faith means: stay within scope, test against your own local instance or your own data (the hosted Playground is static and client-side — everything reproduces locally), don't access or destroy other people's data, don't degrade service for others, and give us the coordinated-disclosure window above. If you're unsure whether something is in scope, ask first — same address.