Top 1% Upwork (8 years) 286+ client deployments 2,036+ projects shipped GoHighLevel Certified Partner Featured speaker: GHL Summit 2025 Client Login
← All issues
The Scale Brief · Issue #143

Your support agent is leaking PII.
The two-line fix most teams miss.

Pull the last 200 RAG-agent conversations from your dashboard right now. I'll wait.

Most RAG-powered support agents quietly leak customer PII. Not in the dramatic "we got hacked" way. In the subtle, persistent, hard-to-detect way that surfaces at SOC 2 audit time when an auditor finds 47 instances of customer A's data showing up in conversations with customer B.

The mechanism is almost always the same. The fix is two lines. Most teams miss both lines because the RAG tutorials they followed don't mention them.

★ The shape of the leak

A support agent retrieves "the most relevant chunks" from a vector store containing all customer records. The chunks are most relevant to the question, not the customer asking it. So a chunk containing Customer A's recent ticket about a refund can be retrieved into Customer B's session — because the words "refund" and "yesterday" happen to vector-match. The LLM then helpfully summarizes details that belong to a different person.

How to detect it in your own stack — 4-minute audit

Open your agent's conversation log. Filter to the last 200 conversations. For each conversation, check:

If you find any of these in 200 conversations, you have the leak. We've audited 60+ RAG support agents and found this in 41 of them. The base rate is roughly two-thirds of production deployments.

The retrieval filter every RAG support agent needs

The fix happens at retrieval, not at generation. Most teams try to fix it at generation ("we'll prompt the LLM not to mix up customers") which fails reliably under load — the LLM doesn't have access to a "this isn't your data" signal because retrieval already injected it into context.

You need to filter the vector store query before the chunks reach the LLM. Most vector stores (Pinecone, Weaviate, Qdrant, pgvector) support metadata filters on the query call. Set customer_id as metadata when you upsert. Pass it as a filter when you query.

Line 1: tag every chunk with customer_id at upsert

# DON'T do this:
index.upsert([(chunk_id, embedding, {"text": chunk_text})])

# DO this:
index.upsert([(chunk_id, embedding, {
  "text": chunk_text,
  "customer_id": chunk.customer_id,
  "doc_type": chunk.doc_type,
  "created_at": chunk.created_at,
})])

Two minutes of work at upsert time. Zero query overhead — metadata is indexed in every modern vector DB.

Line 2: pass customer_id as a filter on every query

# DON'T do this:
results = index.query(vector=q_embed, top_k=5)

# DO this:
results = index.query(
  vector=q_embed,
  top_k=5,
  filter={"customer_id": {"$eq": session.customer_id}}
)

Now the retrieval can only return chunks belonging to the customer asking the question. The LLM never sees other customers' data. The leak is structurally impossible — not "we hope the model behaves," but "the data physically isn't in context."

The edge cases the tutorial doesn't cover

Shared knowledge-base chunks (FAQs, policies)

Some chunks legitimately belong to all customers — a "how do I reset my password" FAQ entry shouldn't be filtered out. Two patterns we use:

Account hierarchies (parent → child accounts)

If Customer A's admin should see Customer A's team's tickets, the filter needs {"account_id": {"$eq": session.account_id}} not customer_id alone. Otherwise admins can't help their own team. Get this wrong and you're back to the leak — but scoped to the wrong axis.

Time-bounded retrieval

For agents that should not reference data older than, say, 90 days (deleted ticket history, GDPR retention windows), add {"created_at": {"$gte": ninety_days_ago_unix}}. Same pattern, same line count, prevents time-leaks.

Why this isn't fixed by your prompt engineering

You can't reliably stop an LLM from summarizing what's in its context window. The model is trained to be helpful with the information present. If you put another customer's data in front of it, it will use that data. Defensive prompts ("only reference the current customer's account") work in test cases and fail in production once context windows fill up and instruction-following degrades under load.

The right architectural answer to "is the LLM behaving correctly?" is "the LLM never had the chance to behave incorrectly because the data wasn't there."

Filter at retrieval. Trust the LLM with only the data the customer is allowed to see. That's the entire fix.

How to verify the fix held

After deploying, rerun the audit from the top of this post 7 days later. The same 200-conversation sample should now show zero instances of cross-customer references. We also recommend permanent monitoring:

For deeper background on the RAG architecture this fix lives inside, see our earlier deep-dive: RAG Configuration Deep Dive. For the broader question of whether your agent layer is actually doing what its dashboard says, see Why Your Follow-Up Agent Should Fail Loudly.

★ Next issue · NOW PUBLISHED Issue #144 — The 3-Second Rule That Doubles AI Conversation Completion. Plus subscribe to The Scale Brief for new technical issues every Sunday.

Enjoyed this? One essay like this every Sunday — 12,400+ founders read it.
Subscribe free RSS

Keep reading

RAG · 15 min read
RAG Configuration Deep Dive
The actual prompts and retrieval logic behind our top-performing client agent. The full RAG architecture stack underneath the PII-fix this post addresses.
Agent Transparency · 8 min read
Why Your Follow-Up Agent Should Fail Loudly
A $40K/mo agency's "autonomous" follow-up was four humans on Slack. The 3 failure modes you want exposed in your agent dashboard.
If you're not sure your agents are clean

Bring your dashboards. We'll audit the leaks.
30 minutes. Live conversation samples.

Adam runs the 4-minute audit on your actual conversation log, finds the cross-customer references if they exist, and scopes the retrieval-filter fix for your stack — whichever vector DB you're on. No pitch deck.

★★★★★

"Adam was great! He gave me some great actionable advice, I left our consultation with a page full of notes. He is a true expert, highly recommend a consultation with him if you need an experts opinion on sales funnel."

30 minute consultation · 2023 · Upwork verified →
★★★★★

"Adam was great! He gave me some great actionable advice, I left our consultation with a page full of notes. He is a true expert, highly recommend a consultation with him if you need an experts opinion on sales funnel."

30 minute consultation · 2023·Upwork verified → · Upwork ✓
★★★★★

"thanks for creating a great funnel for me :)"

Automate + Scale · 1.5h·2021·Upwork verified → · Upwork ✓