今日已更新 80 条资讯 | 累计 20052 条内容
关于我们

Why output-stage PII masking is the wrong protective surface for data exfiltration in RAG

Hashevolution 2026年05月29日 11:10 4 次阅读 来源:Dev.to

"The output filter runs after the LLM has already seen the confidential data. By then, three classes of leak can no longer be stopped. The right surface is retrieval. Walking through a real implementation." TL;DR Most RAG-with-RBAC stacks I see in production put the access-control gate at the output stage: an LLM-response post-filter that masks PII or redacts confidential strings. This is defense-in-depth, not the load-bearing layer. By the time the filter runs, the LLM has already received the confidential context, and three classes of leak — creative paraphrasing, inference, cross-turn persistence — can no longer be stopped by string-matching the output. The protective surface that actually carries the weight is retrieval-stage ABAC: documents and graph nodes the user can't read are never traversed, never make it into the prompt, never seen by the model. The output filter still belongs in the stack, but as the second-to-last line, not the first. This post is a walk through why and how, with code references from a working implementation. It was prompted by a 6-turn LinkedIn DM exchange with Ali Afana (Provia founder, dev.to Featured) on injection-fixture schema design, where the framing crystallized. The seductive default You build a RAG system. You have documents at different sensitivity levels — public, internal, confidential. You want the model to answer based on whichever documents the user is allowed to see. The default mental model: "I'll let the model answer freely, and then I'll filter the response on the way out." This is appealing because: The retrieval pipeline stays simple (one query, one vector search, one response) The access control feels surgical (just before the user, just before damage) The PII-mask vocabulary is well-established (Presidio, regex catalogs, named-entity recognition models) So you wire up something like: Python The seductive default def answer(query, user): chunks = retrieve(query, top_k=10) # No ABAC here context = "\n".join(c.text

本文内容来源于互联网,版权归原作者所有
查看原文