Please do NOT open a public GitHub issue for security vulnerabilities.
Instead, use GitHub's built-in private vulnerability reporting:
- Go to the Security tab of this repository
- Click Report a vulnerability
- Fill in the details β the more context, the faster we can triage
| Stage | Target |
|---|---|
| Initial acknowledgment | 48 hours |
| Triage and severity assessment | 7 days |
| Patch development | Depends on severity β critical issues are prioritized immediately |
| Public disclosure | 90 days after initial report, or sooner if a patch is released |
We follow coordinated disclosure. We will not take legal action against researchers who report vulnerabilities responsibly.
- Authentication & authorization β Supabase Auth integration, JWT verification, RBAC (owner/admin/agent roles)
- API security β All FastAPI endpoints under
/api/ - Widget origin verification β JWT-signed widget tokens (
FUNCTION_SECRET) - MCP OAuth 2.0 server β Authorization code flow with PKCE (RFC 7636), dynamic client registration (RFC 7591), token issuance and verification
- BYOK encryption β Fernet AES-128-CBC encryption of customer-supplied LLM API keys at rest
- Data storage β Supabase PostgreSQL with Row-Level Security (RLS) policies
- Webhook signature verification β HMAC-SHA256 for Lemon Squeezy, WhatsApp Cloud, Slack, and outbound webhooks
- File upload validation β Multipart upload sanitization and Supabase Storage access controls
- Outbound request filtering β SSRF firewall blocking RFC-1918 / loopback IP ranges for crawlers and webhooks
- Third-party managed services (Supabase, LLM providers, Lemon Squeezy) β report to those vendors directly
- Social engineering attacks against project maintainers
- Denial of service (DoS/DDoS)
- Vulnerabilities in dependencies β report upstream; we monitor via Dependabot and
pip-audit - Self-hosted deployment misconfigurations (e.g., exposed
.envfiles, missing TLS)
- Supabase Auth handles user identity with JWT tokens verified server-side via
deps.py - Row-Level Security (RLS) on all Supabase tables β the
service_rolekey is only used server-side, never exposed to clients - Role-Based Access Control (RBAC) with three roles:
owner(full access),admin(configurable tab permissions),agent(restricted to live inbox) - Widget origin tokens β cryptographic JWTs signed by
FUNCTION_SECRETensure widget embed calls originate from allowed domains
- Authorization Code with PKCE (RFC 7636) β mandatory code verifier/challenge for all MCP client authorization
- Dynamic Client Registration (RFC 7591) β MCP clients self-register without pre-shared secrets
- Authorization Server Metadata (RFC 8414) β auto-discoverable at
/.well-known/oauth-authorization-server - Scoped access tokens β
read,write,knowledge,actions,admin
- BYOK keys at rest β customer-supplied LLM API keys are encrypted with Fernet (AES-128-CBC) using
BYOK_ENCRYPTION_KEYbefore storage; decrypted only at inference time in memory - OAuth state tokens β signed JWTs prevent CSRF in OAuth flows
- Webhook signatures β all inbound webhooks are verified via HMAC-SHA256 before processing
- SSRF firewall (
app/core/ssrf.py) β blocks outbound HTTP requests to private/reserved IP ranges (10.x, 172.16β31.x, 192.168.x, 127.x, ::1, link-local) for URL crawlers and webhook deliveries - Rate limiting β distributed fixed-window rate limiter via Upstash Redis REST API with automatic in-memory fallback
- Security headers middleware β Content-Security-Policy, Strict-Transport-Security (HSTS), X-Content-Type-Options, X-Frame-Options
- CORS β strict origin allowlist for dashboard; dynamic origin reflection for widget endpoints only
- Request ID tracing β every request gets a unique
X-Request-IDfor audit trail correlation
- PII scrubber (
app/services/pii_service.py) β redacts credit card numbers, SSNs, and sensitive patterns before LLM inference - Conversation data sovereignty β all data stays in the customer's own Supabase project
- No telemetry β self-hosted instances send zero data to PersonaliAI
| Secret | Purpose | Rotation Guidance |
|---|---|---|
SUPABASE_SECRET_KEY |
Server-side Supabase access (bypasses RLS) | Rotate via Supabase dashboard β Settings β API β Regenerate |
FUNCTION_SECRET |
Signs widget origin JWTs and OAuth state tokens | Regenerate with python -c "import secrets; print(secrets.token_urlsafe(32))" β existing widget tokens will be invalidated |
BYOK_ENCRYPTION_KEY |
Encrypts customer BYOK LLM keys at rest | Generate with python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" β rotating this invalidates all stored BYOK keys |
GEMINI_API_KEY |
Default LLM provider | Rotate via Google AI Studio |
- Never commit a filled
.envfile β all.envfiles are gitignored - Use a secret manager (Vault, AWS Secrets Manager, GCP Secret Manager, Railway/Render built-in secrets) in production
- OAuth client secrets (Google, Microsoft, Zoom) should be rotated annually
| Tool | What it does | Frequency |
|---|---|---|
Dependabot (.github/dependabot.yml) |
Watches pip, npm, Docker, and GitHub Actions dependencies | Weekly |
pip-audit |
Scans Python dependencies for known CVEs in CI | Every push/PR to main |
CodeQL (.github/workflows/codeql.yml) |
Static analysis for common vulnerability patterns | Every push/PR to main |
Secret scanning (.github/workflows/secret-scan.yml) |
Detects accidentally committed secrets | Every push/PR to main |
| Version | Supported |
|---|---|
Latest main branch |
β Active security updates |
| Older commits / tags | β No backports β update to latest |
We do not maintain separate release branches. Security fixes are applied to main and released immediately.
We follow coordinated disclosure:
- Reporter submits via GitHub's private vulnerability reporting
- We acknowledge within 48 hours and begin triage
- We develop and test a fix
- We release the patch and publish a GitHub Security Advisory
- The reporter is credited (unless they prefer anonymity)
- Full details are disclosed 90 days after the initial report, or immediately upon patch release β whichever comes first
We will never pursue legal action against security researchers acting in good faith.
- Always deploy behind TLS (HTTPS) β use a reverse proxy like Caddy, nginx, or your platform's built-in TLS
- Set
CHATTY_BACKEND_URLandCHATTY_FRONTEND_URLto your real production domains - Use the session pooler or direct connection string for migrations, not the transaction pooler
- Keep your Supabase
service_rolekey strictly server-side β never expose it in frontend code or client-side configuration - Enable Supabase's built-in email confirmation for sign-ups in production
- Review and restrict the
allowed_domainslist for each bot to prevent unauthorized widget embedding - Monitor
docker compose logsand Sentry (if configured) for anomalous patterns
Questions about security? Open a discussion (for general questions) or use private vulnerability reporting (for vulnerabilities).