Skip to content

Security: mamta-epili/RAGchatbot

Security

SECURITY.md

Security policy

Reporting a vulnerability

Please do not open a public issue for security problems. Use GitHub's private vulnerability reporting on this repository, or email the maintainer listed in package.json.

Include a description, reproduction steps, and the versions affected. Expect an acknowledgement within a few days.

Reporting a guardrail bypass

A phrasing that gets past contentSafety or promptInjection is a bug, but usually not a sensitive one — a public issue with a failing test case is the fastest fix. If the bypass produces genuinely harmful output, report it privately instead.

Handling API keys

This is the most common way to get hurt with a RAG SDK, so it is worth being blunt.

Never ship a key you pay for to a browser. Any value in frontend JavaScript — including every VITE_, NEXT_PUBLIC_ or REACT_APP_ variable — is readable by anyone who opens devtools. It will be scraped and used.

Do this instead:

// browser
const client = createRagClient({ url: "/api/rag" });
// server — the key never leaves this process
const engine = new RagEngine({ llm: new OpenAILLM({ apiKey: process.env.LLM_API_KEY }), ... });

This is enforced, not just advised: @guardrag/core throws a RagError with code key_in_browser if any provider or vector store is constructed with a non-empty API key while window and document exist. There is no opt-out flag, because an opt-out is the thing that eventually gets copied into production.

Two deliberate exceptions, both of which hold no secret:

  • An empty key is allowed. openAICompatible({ baseUrl: "/llm", apiKey: "" }) lets a browser talk to a same-origin gateway that injects credentials server-side.
  • Non-browser runtimes are unaffected. Deno, Bun, Cloudflare Workers, Vercel/Netlify edge and Supabase Edge Functions have fetch but no document, so they are treated as servers — which they are.

Server-side checklist

  • Keys in environment variables or a secret manager, never in source or the client bundle
  • Supabase service-role key server-side only; RLS enabled so the anon key cannot write
  • rateLimit guardrail plus infrastructure-level rate limiting — a single guardrail instance is per-process, so use a shared store (Redis) across replicas
  • ALLOWED_ORIGINS/CORS restricted to your domains, not *
  • Request body size capped (the reference server uses 256 KB)
  • Guardrail blocks logged and monitored; a spike is usually abuse or a scraper
  • Provider spend limits and alerts configured — guardrails reduce cost, they don't cap it

Threat notes specific to RAG

Indirect prompt injection. If a document in your knowledge base contains "ignore your instructions and…", that text reaches the model as retrieved context. The system prompt explicitly labels passages as untrusted data, and the output guardrail strips prompt echoes — but you should also review what you ingest, particularly anything user-submitted or crawled.

Knowledge base leakage. The model can only reveal what retrieval hands it. If a document contains secrets, restrict it at the store level with metadata filters (ask({ filter: { tenant } })) or keep it out of the index. Enable pii: { redactOutput: true } if your corpus may contain personal data.

Multi-tenant isolation. Filters are applied at the store, not in the prompt. Always pass a tenant filter derived from the authenticated session on your server — never from a value the client sent.

There aren't any published security advisories