Security
Gumm is a self-hosted personal assistant. Understanding its security model helps you deploy it safely and know what protections are in place.
Threat model
Gumm is a single-user, self-hosted system. The primary threat is:
An attacker on the network reaches the Gumm HTTP API and attempts to authenticate, extract data, or abuse the LLM.
Secondary threats:
- A malicious or buggy module causes unintended behavior
- Sensitive data leaks to the LLM (and thus to the LLM provider)
- The Telegram bot is accessible to unauthorized users
Security layers
1. VPN Guard (network layer)
When you enable Tailscale or NetBird, a middleware validates that every incoming request originates from a VPN IP range. Requests from outside the VPN are rejected before reaching any route handler.
VPN-bypassed paths (must be reachable externally):
/api/health— health checks/api/setup/*— first-run setup/api/telegram/webhook— Telegram push notifications/api/webhooks/*— external webhook integrations
Recommendation: always deploy with VPN enabled. It is the single most effective security control.
2. Authentication
- All API routes require a valid session cookie (except health and setup)
- The session is an encrypted, HMAC-signed cookie powered by
nuxt-auth-utils - Sessions expire after 7 days
- The admin password is stored as a bcrypt hash (cost 10) — never in plain text
- Minimum password length: 12 characters
- No default password — setup must be completed before the first login is possible
3. Rate limiting
Redis-backed sliding-window rate limiting protects against brute force and abuse:
| Endpoint | Limit | Window |
|---|---|---|
Chat (/api/chat) | 30 requests | 60 seconds |
| Chat burst | 5 requests | 5 seconds |
| General API | 100 requests | 60 seconds |
Auth (/api/auth/*) | 10 requests | 5 minutes |
When Redis is unreachable, an in-memory fallback applies the same limits with lower guarantees.
4. Guardrail — Data Loss Prevention
Every user message is scanned before reaching the LLM. The following patterns are automatically detected and blocked:
- Credit card numbers (Visa, Mastercard, Amex, JCB)
- API keys: OpenAI, Anthropic, GitHub, Stripe, Discord
- AWS Access Key / Secret Key pairs
- JWT tokens, Bearer tokens, Basic Auth credentials
- SSH and PEM private keys
- Social Security Numbers (US SSN, French NIR)
- Database connection strings with embedded credentials
- Generic hex tokens ≥ 32 characters
When a pattern matches, the request is rejected with HTTP 400 and a clear error message. The data never reaches the LLM.
Additionally, you can manually wrap sensitive values in [[...]] to have them stripped and stored as secrets instead:
“My API key is [[sk-proj-abc123xyz]]”
Gumm stores the value in the secret vault and replaces it with [REDACTED] in the message.
5. Module security
- Every module’s
manifest.jsonis validated against a Zod schema before the module code is imported - Official modules are disabled by default — users must explicitly enable them
- Module status is stored in the database; a module disabled in the DB is never imported even if its files are present on disk
- If a module throws during load or execution, only that module fails — other modules and the server continue normally
- Module code cannot access environment variables or the filesystem outside of designated paths
6. Telegram security
- All incoming Telegram messages are validated against a chat ID whitelist before any LLM call
- Messages from unknown chat IDs are silently dropped
- The bot token is stored in the database, never in env vars or source code
7. Redis security
Redis is bound to 127.0.0.1 only in the Docker Compose configuration. It is never exposed to external networks.
Secret vault
Gumm includes a built-in credential store for your third-party passwords and tokens:
- Stored in the SQLite database (
user_secretstable) - Passwords are stored as SHA-256 + random salt (hashed, not reversible)
- Non-password values (API keys, tokens) are stored as-is to allow the LLM to use them via the
get_secrettool - The dashboard shows masked values only — the raw value is never shown in the UI
Deployment hardening checklist
Use this checklist before making your Gumm instance accessible:
-
GUMM_ADMIN_PASSWORDis set to a strong, unique password (12+ characters) -
NUXT_SESSION_PASSWORDis set to a random 32+ character string (openssl rand -hex 32) - Tailscale or NetBird is configured and
VPN_BIND_IPis set to the VPN IP - Redis is not exposed outside the Docker network (default — do not change)
- HTTPS is enabled via Caddy or a reverse proxy
- Telegram
allowedChatIdsis set if Telegram is enabled - A backup of the
gumm-datavolume exists
Port exposure
| Port | Service | Recommendation |
|---|---|---|
3000 | Gumm web app | Bind to VPN IP only (VPN_BIND_IP) |
6379 | Redis | Already bound to 127.0.0.1 — never expose |
80 / 443 | Caddy (optional) | Bind to VPN IP or public IP with TLS |
Updates and patches
Security patches are applied in new releases. Keep your instance up to date:
git pull
docker compose build --no-cache gumm
docker compose up -d
Audit history
A full security audit was conducted in March 2026. All identified vulnerabilities (critical, high, medium, and low) have been resolved. See the internal audit documents for details:
- Security Architecture — detailed description of each security layer
- Vulnerabilities — identified issues (all fixed as of March 2026)
- Recommendations — applied remediations