Inspiration
AI agents are being connected to inboxes so they can triage email, draft replies and prepare summaries. Today that access is all-or-nothing: connect an agent and it can read everything, including verification codes, bank statements, medical results and family members' addresses. People notice. One Reddit thread in an agent community asks, "Email access: anyone crazy enough to give your agent access?"
Forbes' October 2026 guide "Can You Trust AI?" lists what never to share with AI: "passwords, login credentials, authentication codes, SSNs, bank details, personally identifiable information." It warns that connecting an AI tool to your Gmail means "the chatbot being able to access information that you didn't give it explicit permission to access." Its fix is to remove those details yourself before you type. But once an agent reads your inbox, you're no longer the one choosing what it sees. Every privacy tool we found protects the company building the agent. We wanted a tool for the person whose data it is.
Our target user: freelancers and solo founders who run their business and their life out of one inbox. They want an agent's help with client work, and no company IT department protects them.
What it does
Spindle is a user-side privacy gateway between AI agents and your email. Agents connect to Spindle over MCP instead of getting the whole inbox. For each agent, Spindle decides:
- Which emails it may see: each category (work, travel, finance, health, auth, personal…) is allow, ask or deny. Anything uncategorized is denied by default.
- What gets redacted in the emails it sees: verification codes, reset links, card numbers (with a Luhn check), SSNs, bank account and routing numbers, medical record and insurance IDs, medications, dates of birth, street addresses, phone numbers, plus custom rules (e.g. salary figures). There are three protection levels.
- When to ask you: sensitive categories are held in a live approval queue, and the agent's request waits while you click Approve or Deny. Approval unlocks access, but redaction still applies.
- What to quarantine: emails with hidden-text instructions (white or 1-pixel text) or prompt-injection patterns are withheld before the agent sees them.
- What it logged: an audit trail of the exact text each agent received, with an inspector that shows the original next to what the agent saw.
It works with any MCP agent. Our demo uses Cursor CLI with Grok, and Claude Code configs are included. The same inbox gives different agents different views.
Measured on our 17-email demo inbox (fictional persona, same prompt):
- Ordinary connector: all 17 emails exposed, 21 sensitive values + 17 sender addresses. In 6 of 6 runs the agent repeated Mom's home address and phone, a salary offer and a medical appointment in its answer.
- Through Spindle: 7 emails returned; 5 withheld (auth and health), 3 held for approval, 2 injection emails quarantined. Approved emails arrive with account numbers, addresses and phones redacted.
- Bypass attempts: when asked to read Spindle's files directly, the agent tried (shell, file read, glob) and was blocked by its permission rules in 3 of 3 attempts, with 0 leaks.
How we built it
- Gateway (Python 3.12): the MCP server (MCP SDK 2.x, stdio locally and Streamable HTTP in the cloud); a policy engine with order quarantine → deny → ask → allow; a 16-stage deterministic redaction engine; hidden-text detection by parsing the HTML; pattern checks for injections; SQLite (WAL) for the audit log, approvals and the classification cache.
- Classifier: rules first, plus an LLM signal through any OpenAI-compatible endpoint (local Ollama by default; cloud Meta Muse used during development). Text is redacted at the strictest level before any LLM sees it, and the LLM can never override the deterministic rules. If it fails, Spindle fails closed.
- Dashboard: FastAPI + HTMX, with a live audit feed, approval queue, inspector, per-agent protection level and an outbox. Locally it uses token authentication.
- Policy assistant: turns plain-English rules into policy changes using Claude. Spindle computes the diff deterministically, and anything that loosens privacy needs explicit confirmation. Claude only ever sees policy text, never email.
- Governed sending: a
send_emailtool that writes to an outbox, with a recipient allowlist, approval for new recipients, a block on addresses that only appear in quarantined email, an outbound secret scan, and rate limits. - Azure: the project site on Static Web Apps. A hosted gateway on App Service: the dashboard sits behind Microsoft Entra ID login, restricted to the owner's account. Remote MCP for cloud agents authenticates per-agent keys, so the server works out which agent is calling instead of trusting the agent's word. Unauthenticated callers fall into a deny-all policy.
- Testing: 87 automated tests, plus scripted end-to-end checks driving the real agent CLI.
Challenges we ran into
- Over- and under-redaction. Early OTP rules redacted years, PR numbers and dates, which mislabeled work email as "auth". The fixes had to keep real codes ("48 29 13", "Enter 482913… code expires") while leaving "code freeze 2026" alone.
- Agent timeouts: the CLI cuts tool calls off at about 60 seconds, so the approval window had to fit inside that.
- Cloud authentication: our first Azure deployment trusted identity headers without the platform's authentication turned on. Our own review caught that a forged header could reach the dashboard. We enabled Entra ID at the platform level, ignore principal headers unless the platform confirms auth is on, and re-tested the attack live.
- Per-agent identity in a shared server: we had to resolve identity per tool call, not per process, so concurrent agents can't get each other's view. A test interleaves 20 calls between two agents to prove it.
Accomplishments that we're proud of
- A working before/after that anyone can read: same agent, same question, and the private details simply aren't there.
- Every guarantee is deterministic. The LLM is only an extra signal, and every number we quote was measured.
- A bypass attempt by the agent itself, blocked and logged.
- A hosted version with real Microsoft login and per-agent keys, built and security-reviewed in one evening.
What we learned
- Modern models are getting good at refusing obvious attacks. The bigger problem is what they're allowed to read in the first place. Data minimization beats detection.
- Users need control at the moment of access, through approval, not only in a settings page.
- "Who is asking?" matters as much as "what is asked". Agent identity has to be authenticated, not self-declared.
What's next for spindle
- Attachments: the same rules for PDFs and documents (IDs, tax forms, leases); faces detected locally in photos, withheld or blurred by default.
- Real Gmail (read-only) and more sources: calendar, drive, messages.
- Governed writes in production: drafts by default, approval for new recipients.
- Trust for the hosted version: policies signed by the user's device; keys only the user can unlock; reproducible builds; open source throughout. Deployment modes: local, self-hosted, or hosted.
- Fine-tuned small local models for classification.
Built With
- azure-app-service
- azure-static-web-apps
- beautiful-soup
- claude
- cursor-cli
- fastapi
- grok
- htmx
- mcp
- meta-muse
- ollama
- pydantic
- python
- sqlite
Log in or sign up for Devpost to join the conversation.