Inspiration
Companies want AI agents living inside their real communication channels — Slack, email, SMS — because that's where the actual work happens. But the moment a message from an internal channel gets forwarded to a cloud LLM, whatever's inside it leaves the building: an internal IP, a customer's email, an API key, a name, a card number fragment.
This is one of the most cited blockers to enterprise LLM adoption. Most teams "solve" it by not solving it — they just never connect their sensitive channels to an LLM at all, or they self-host a model, which is expensive, slower, and still requires trusting a pile of new infra.
We wanted to build the layer that removes that objection entirely: let the agent live in the real channel, but make sure the model never sees what it shouldn't.
What it does
Privacy Guard sits between a Caspian-connected agent and the LLM it calls.
- A message arrives on Slack or Email, both wired to the same
on_messagehandler. - Before it reaches the LLM,
sanitize()scans the text — regex for emails, IPs, credit cards, API keys, and phone numbers; spaCy NER for names — and replaces every sensitive span with a typed placeholder like[IP_ADDRESS_F5BA]. - The real values are encrypted locally (Fernet) and held in an in-memory, TTL-bound map — never written to disk, never sent anywhere.
- The LLM (running on Featherless.ai, our inference partner) reasons only over the safe text. Because placeholders are typed, it stays logically coherent — it can still say "please whitelist
[IP_ADDRESS_F5BA]." restore()decrypts and re-injects the real values right beforemessage.reply()sends the answer back out.
The same sanitize/restore pair is also exposed as a standalone MCP server, so any MCP-capable client — Claude Desktop, Cursor, or another agent entirely — can call the same redaction layer directly, not just our demo agent.
How we built it
caspian-sdkfor the channel layer — oneon_messagehandler, connected to Slack and Email, satisfying the multi-channel requirement without writing separate integration code per platform.- Featherless.ai for inference — OpenAI-compatible, so swapping models is a one-line change, not a rewrite.
- Regex + spaCy NER for detection — regex handles structurally predictable data (emails, IPs, card numbers with Luhn validation, API-key-shaped strings) reliably; NER catches names and orgs on a best-effort basis.
cryptography's Fernet (AES-128-CBC + HMAC-SHA256) for encrypting the real values in the in-memory vault — a standard, audited library, not custom crypto.- MCP (
mcpPython SDK) to exposesanitize/restoreas reusable tools over stdio, wired into Cursor via.cursor/mcp.json. - Property-based tests (via
hypothesis) fuzzing the sanitize → restore round trip to make sure nothing gets corrupted or lost on the way back out.
Challenges we ran into
- Keeping the LLM's output coherent without ever seeing real data. Plain random tokens make the model's reasoning fall apart. Typed, deterministic placeholders (
[EMAIL_A1B2]instead ofxJ9$2z) fixed this — the model still understands what kind of thing it's talking about. - Making sure the LLM doesn't mangle the placeholders. An LLM "helpfully" reformatting
[IP_ADDRESS_F5BA]into something slightly different would silently break the restore step. We handle this with an explicit system-prompt instruction to copy placeholders verbatim. - Overlapping spans. A credit-card-shaped number sitting next to an API key needed careful right-to-left span replacement and category-priority resolution so nothing gets double-tagged or corrupted.
- Being honest about detection limits. Regex is reliable for structured data, but names have no fixed pattern — NER will miss edge cases. We chose to disclose this clearly rather than overclaim "we catch everything."
- Avoiding infinite reply loops. The agent needed to recognize and ignore its own messages and only respond to group-channel mentions, not every message in a channel.
What we learned
- Redaction-before-LLM is a real, established pattern (the same category of technique used by tools like Microsoft Presidio) — it's not a gimmick, it's a legitimate answer to a real enterprise adoption blocker.
- It's not a cryptographic zero-knowledge proof, and it's important to call it what it actually is: local tokenization with key custody. Overselling the security story is worse than being precise about it.
- Building this as a layer, not a standalone product, made it a genuine complement to what Caspian already does — Caspian gets agents into real channels; Privacy Guard is the missing piece that makes enterprises comfortable letting them stay there.
What's next
- Configurable per-category redaction policy (e.g. "always redact API keys, never redact names") for different risk tolerances.
- Deploying the MCP server over HTTP/SSE so it's remotely callable, not just spawned locally.
- Expanding channel coverage (Telegram, WhatsApp) through the same handler, no new architecture needed.
Log in or sign up for Devpost to join the conversation.