Do not open a public GitHub issue. Email security@rebarlabs.io with:
- A description of the issue and its impact.
- Steps to reproduce (or a proof-of-concept).
- Affected commit / version.
- Whether the issue is already public anywhere.
You should get an acknowledgement within 5 business days. If the report is in scope and reproducible, we'll work with you on a fix and coordinate disclosure.
In scope:
- The API server (
src/), MCP wrapper (mcp/), and helper scripts (scripts/). - Anything that handles OAuth tokens, JWTs, or could leak email content across user namespaces.
Out of scope:
- Self-inflicted misconfiguration (e.g. running with
JWT_SECRET=replace-me). - Findings in third-party dependencies — please report those upstream.
- DoS via unbounded ingestion (cap is documented and tunable).
- OAuth refresh tokens for Gmail/Outlook — encrypted at rest with AES-256-GCM using
TOKEN_ENCRYPTION_KEY. If that key leaks, every stored refresh token is compromised; rotate the env and force every user to reconnect. - Long-lived JWTs — minted via
pnpm run mint-tokenfor the MCP integration, 7-day expiry. Treat them like passwords. - Per-user namespace isolation — enforced server-side from the JWT
sub, never from request bodies. Any path that lets a user influence the namespace is a high-severity bug. - Raw email text is never persisted in Postgres — only metadata + the vector in Pinecone. A bug that writes raw bodies to the DB or logs is a bug.
- All SQL queries are parameterized via the
pglibrary — the codebase never uses string interpolation to assemble queries. - Structured logs with redaction:
pinois configured to dropaccess_token,refresh_token, andauthorizationkeys before serialization (src/logger.ts). Adding a new sensitive field? Add its path to the redact list.
- Gmail cleanup moves messages to Trash via
batchModify(addLabelIds: TRASH); Gmail auto-empties Trash after 30 days. - Yahoo / IMAP cleanup moves messages to the Trash folder via IMAP
UID MOVE(RFC 6851). Retention depends on the user's Yahoo account setting — unlike Gmail, there's no fixed 30-day window. - XOAUTH2 is always over TLS (port 993,
secure: true); the IMAP adapter refuses to connect without it. - Yahoo refresh tokens expire after roughly 60 days of inactivity. When refresh fails, the account is flagged
needs_reauth = true; re-run the OAuth flow for that account to mint fresh tokens.
This server is designed to run behind a trusted boundary — your own localhost, a VPN, or a reverse proxy you control. It deliberately does not implement:
- Rate limiting. The project assumes a small number of trusted users; if you expose it to the public internet, run it behind a proxy (nginx, Caddy, Cloudflare) with per-IP/per-token rate limits.
- Multi-tenant defense in depth. Namespace isolation is enforced in code, but the server trusts any valid JWT. A leaked JWT = full access to that user's namespace until expiry.
- HTTPS termination. The server speaks plain HTTP on
:3000by default. OAuth redirect URIs for production must behttps://— terminate TLS at your proxy.
Input size limits that are enforced:
express.json({ limit: "1mb" })on all JSON bodies.- Search query ≤ 500 chars,
top_k≤ 50,account_ids≤ 20 (src/routes/search.ts). - Cleanup rule arrays capped (senders ≤ 100, labels ≤ 50, subjectMatches ≤ 50),
maxMessages≤ 5000 (src/cleanup/rules.ts).
This is a hobbyist / self-hosted project. There is no bug bounty, no SLA, and no guarantee of a fix timeline. Responsible disclosure is appreciated but not contractually rewarded.