Skip to content

Latest commit

 

History

History
65 lines (51 loc) · 3.21 KB

File metadata and controls

65 lines (51 loc) · 3.21 KB

Security Policy

Reporting a vulnerability

If you discover a security vulnerability in ragdesk, please report it privately by opening a security advisory. Please do not open a public issue for security problems.

We aim to acknowledge reports within 72 hours.

Supported versions

ragdesk is in active development; security fixes target the main branch.

Automated scanning

  • Dependabot keeps Go, Python, Docker and GitHub Actions dependencies patched.
  • govulncheck scans the Go service for known vulnerabilities on every CI run.
  • CodeQL statically analyses the Go and Python code on every push.

API key model

Programmatic /v1 keys (rd_live_…) are real secrets, unlike widget keys: only a SHA-256 hash is stored, the full secret is returned exactly once at creation, and listings show a display prefix. Keys carry least-privilege scopes (chat, documents), are limited per key (60 questions/min) on top of workspace quotas, track last use, and revocation (kept, auditable) cuts access immediately. Treat a leaked key like a password: revoke it and mint a new one.

Crawler safety

The docs crawler only ever fetches what a workspace member explicitly asked for, and is hardened against SSRF: http/https only; private, loopback, link-local (incl. cloud metadata) and multicast destinations are refused at dial time — after DNS resolution, on every redirect hop — so a hostname pointing at an internal address is caught regardless of spelling; response bodies, timeouts, redirect counts and sitemap fan-out (25 pages) are all bounded. Crawled pages count against the workspace's document cap; the crawler assumes you own the docs you crawl (it does not evaluate robots.txt).

Widget trust model

The embeddable widget intentionally works without user auth, so its security model is worth spelling out:

  • The widget key is public. It ships in customer page source (rdw_…) and only names a workspace — possession grants nothing by itself.
  • The gates are server-side: the browser Origin header must match the key's allowlist exactly (scheme + host + port, normalized); requests pass a per-IP limit and a per-key budget (60 questions/min) backed by Redis; every question draws down the workspace's monthly plan quota (402 when exhausted); revoking a key (kept, auditable) cuts access immediately.
  • Thread isolation: widget conversations are stored with source = 'widget' and the public endpoint can neither read nor extend in-app threads; a widget key never exposes documents, members or billing.
  • XSS containment: widget.js renders exclusively via textContent inside a closed shadow root — model output can never inject markup or styles into the host page.
  • Known limits (accepted): a non-browser client can forge the Origin header, which is why rate limits and the plan quota — not the origin check — bound abuse; visitor questions are visible to the workspace's members in the conversation list (surface this in your own privacy notice); and, as with any LLM product, retrieved documents plus visitor questions form the prompt, so treat model output as untrusted content — the UI already does.