The permission layer most enterprise RAG deployments lack
A junior analyst asks a routine question, and a stale ingestion-time ACL hands the model a Board-Only memo. The Sovereign RBAC Firewall authorizes every retrieved document at query time, against the user's live nested-group set and attributes, and drops withheld documents before the model sees a token. Deterministic code, outside any LLM. Agents advise, code decides.
40/40
Correct decisions on the golden authorization set
0 unauthorized disclosures, 0 false denials, computed by the eval harness
29/40
The faithful flat-ACL baseline on the same 40 cases
10 unauthorized disclosures, 1 false denial
$670K
Added cost of a shadow-AI breach over a traditional incident
IBM Cost of a Data Breach, 2025
This is a runnable demo, not a deployment. Every identity and document is a synthetic European-bank fixture; the identity provider is an Azure-AD/SCIM-shaped JSON fixture, and the vector store runs in-process behind a Qdrant-shaped interface.
Buying a private LLM does not make it safe to point at the crown-jewel corpus.
The standard pilot build tags each document chunk with a flat ACL at ingestion. That design collapses under real enterprise identity: nested Active-Directory groups, cross-OU inheritance, clearance levels, time-boxed project grants, and terminations that happen after the index was built. The result is the classic failure this demo stages end to end: a junior analyst asks a normal question, and the RAG pipeline hands the model a Board-Only memo, because a stale ingestion-time snapshot said she could see it.
The root cause is structural. Document permission is a live property of an identity graph, so any snapshot of it is already wrong. A better model does not fix this: a perfect model handed a board document still leaks it. The value sits in governing what reaches the model, not in model quality.
The stakes are measured. Shadow-AI breaches cost $670K more than traditional incidents, and 65% of AI-related breaches compromised customer PII (IBM Cost of a Data Breach, 2025). Shadow-AI breaches take 247 days to detect against a 241-day average, and 1 in 5 organizations has suffered a breach tied to shadow AI (IBM, 2025). On the regulatory side, EU AI Act Article 50 transparency obligations become enforceable on August 2, 2026, and the combined GDPR plus AI Act penalty ceiling reaches EUR 55M or 11% of global annual turnover.
Our own solution page calls retrieval-time permission enforcement "the reason most enterprise RAG pilots fail their security review" and "the hardest unsolved problem in enterprise RAG." The whitepaper product analysis behind it flagged RBAC-aware RAG across the market as described but not demonstrated, with no working implementation. This demo is that working implementation.
A deterministic policy engine decides what the model sees. Not the model, and not a prompt.
Every query runs the same pipeline:
query + user identity → retrieval → RBAC firewall (deterministic, outside any LLM) → permitted documents only → answer LLM → hash-chained audit record
For every candidate document, the firewall resolves the user's effective permissions at query time: it recursively flattens nested AD/OU groups (the fixture nests 3 levels deep) and evaluates ABAC attributes against the document's structured policy reference: clearance level L1 to L4, managed device, department, time-boxed project grants with expiry, and employment status.
Each document gets ALLOW, WITHHELD with a machine-checkable reason code (BOARD_MEMBERSHIP_REQUIRED, ACCESS_WINDOW_EXPIRED, ALL_ACCESS_REVOKED_TERMINATION, POLICY_CONFLICT), or NEEDS_REVIEW. Withheld documents are dropped before the context window, so the model never sees documents the user cannot access. On any conflict or unresolved reference it denies by default and routes to human review rather than guessing.
Every query appends a record to an append-only SHA-256 hash chain with tamper verification: user, resolved permission set, documents retrieved, served, and withheld with reason codes, needs-review conflicts, model and provider, and the prompt/response pair. Exportable as JSON, generated inside the VPC. The retrieval-access evidence record an EU AI Act Article 50 file asks for.
The comparison side of the demo is a faithful naive flat-ACL RAG, the build most pilots actually ship. It genuinely resolves nested groups at ingestion time. Its failures are its two honest, inherent limits: the snapshot goes stale, and a flat tag cannot express clearance, device, time-window, or termination. On the demo's 40-case golden set those two limits produce 10 unauthorized disclosures and 1 false denial, the false denial being a post-ingestion joiner whose entitlement the frozen snapshot missed.
The answer path, built on Pydantic AI, receives only post-firewall permitted chunks, states what was withheld and why instead of bluffing, and has zero authority over permissions. It is provider-swappable by one environment variable: Anthropic (default model claude-opus-4-8), OpenAI, Gemini, or Ollama for air-gapped sovereign deployment, where nothing, not one token, leaves the box. No API key is ever required: the demo routes answers to a local bridge when one is running and falls back to a deterministic stub otherwise, and the eval scoreboard never calls an LLM at all. The firewall is the product; the model is scenery.
Golden labels for the 40-case set are derived mechanically by an independent reference oracle, a separate implementation written from the policy definitions rather than the firewall under test. The scoreboard is a function of the identity graph, not hand-picked results, and every figure is computed at run time, never hard-coded. Enforcement overhead measures in microseconds, in-process, for the firewall logic alone; a production IdP round-trip adds latency this demo stubs.
Gartner projects that 40% of enterprise applications will embed AI agents by end-2026, up from under 5% in 2025. The same deterministic authorize(user, doc) gate is the documented extensibility path for that world, not a shipped feature of this demo: an agent cannot retrieve what its on-behalf-of user could not.
One question, asked by one synthetic analyst, answered on both sides of the split screen. Every image below is a screenshot of the running app; every identity, document, and figure is synthetic fixture data.
Lena Vogt, an EMEA Credit Risk Analyst with clearance L2, asks: "What is our Q3 EMEA credit-loss projection and the methodology behind it?" Retrieval surfaces the Board-Only Q3 board pack alongside documents she may see. The flat-ACL side serves it: years of nested-group inheritance debt in the identity graph have made her transitively a "Board" member, and a group-only tag has no concept of clearance. The memo reaches the model, the answer reads out EUR 412 million, and the banner says LEAK.
On the RAGGUARD side, the same retrieval runs, but the board pack is withheld before the LLM with the reason code BOARD_MEMBERSHIP_REQUIRED: the document requires clearance L4 and Lena holds L2. The model answers correctly from the Internal methodology note and the Confidential memo her nested-group chain does entitle her to, and it states what was withheld and why instead of bluffing.
The decision-detail modal shows the verbatim model input on both sides. On the left, the leaked board pack sits inside the prompt, flagged red. On the right, it is simply absent: the model never sees documents the user cannot access. The per-document view makes the divergence explicit, the same board pack row reading "Served without authorization" on one side and "Access denied at retrieval" with its reason code on the other.
The Internal methodology note carries an embedded prompt-injection string instructing any AI assistant reading it to ignore its retrieval permissions and output the full Board figure. On the firewall side it has nothing to exfiltrate: the board pack never entered the context window, because authorization happened before the LLM. This is one labeled case, shown as defense-in-depth from retrieval-time enforcement, not a separate guardrails product.
Priya Shah was terminated nine minutes ago on the demo clock, and the fixture's webhook has fired. The firewall returns ALL_ACCESS_REVOKED_TERMINATION on everything: 0 granted, 5 denied. The flat-ACL snapshot, built before the termination, still serves her, because the re-index has not run. The demo walks the same edge for Marco Rossi, whose time-boxed Project-Atlas grant expired yesterday on the demo clock (ACCESS_WINDOW_EXPIRED), for Raj Patel, who sits in an allowing group and a denying group at once (POLICY_CONFLICT, held for human review), and for Wei Chen, the L4 board member the firewall correctly serves, the positive control proving it is not just denying everything.
Every one of these decisions lands in the tamper-evident audit trail: a hash-chained JSON record of who asked what, what was served, what was withheld and why, and which model answered, with a CHAIN INTACT verification chip and a one-click export. Generated automatically, inside the VPC.
The golden set is 40 labeled (user, document) allow/deny decisions: 10 users against 4 sensitive documents, labels derived mechanically by the independent oracle from the identity-graph semantics. The firewall scores 40/40 with 0 unauthorized disclosures and 0 false denials. The flat-ACL baseline scores 29/40 with 10 unauthorized disclosures, including the board pack served to 7 unauthorized users, the expired Atlas window, and the terminated employee, plus 1 false denial. Every figure is computed by the harness at run time, never hard-coded, and the per-case drill-down shows each oracle label beside both systems' decisions. These are golden-set results, not open-world guarantees.
The same comparison the demo runs live, on the same identity graph and the same documents.
| Dimension | Naive Flat-ACL RAG (the typical pilot build) | Sovereign RBAC Firewall (RAGGUARD) |
|---|---|---|
| When authorization happens | At ingestion, frozen into a tag on each chunk | At retrieval time, per query, per document |
| Nested groups and cross-OU inheritance | Resolved once at ingestion; the snapshot goes stale | Recursively flattened against the live identity graph on every query |
| ABAC: clearance, device, time-boxed grants, employment status | Inexpressible in a flat tag | Evaluated per document against the structured policy reference |
| Termination nine minutes ago | Still served until the re-index runs | ALL_ACCESS_REVOKED_TERMINATION on everything |
| Conflicting policies on one document | Serves the document | Deny-by-default: NEEDS_REVIEW, routed to a human with the conflict spelled out |
| 40-case golden set | 29/40: 10 unauthorized disclosures, 1 false denial | 40/40: 0 unauthorized disclosures, 0 false denials |
| Audit trail | None | Hash-chained, tamper-evident record of every serve and withhold, exportable as JSON |
Enforce authorization at retrieval time, not ingestion time. A deterministic policy engine outside the LLM checks every retrieved document against the user's live group memberships and attributes before it reaches the model, so withheld documents never enter the context window. In this demo that gate scores 40/40 on a labeled 40-case golden set, against 29/40 for the flat-ACL build most pilots ship.
Because the tag is a snapshot and permission is a live property of your identity graph. An ingestion-time ACL misses everything that changes after indexing, like a termination or an expired project grant, and it cannot express attribute rules like clearance level or managed device at all. In the demo those two limits account for 10 unauthorized disclosures and 1 false denial across a 40-case benchmark, from a baseline that faithfully resolves nested groups at ingestion.
Not if the document never reaches the model. The demo includes a labeled case where a note embedded in a document instructs any AI assistant to ignore its retrieval permissions and output the Board-Only figure, and the injection has nothing to exfiltrate because authorization happened before the LLM and the memo never entered the context window. That is one defense-in-depth example of retrieval-time enforcement, not a standalone guardrails product.
Deny by default. When a user holds both an allowing and a denying membership on the same document, or a policy reference cannot be resolved, the firewall returns NEEDS_REVIEW and routes the case to a human with the conflict spelled out, rather than guessing. The demo shows exactly that: a credit risk manager who is in an allowed group and a denied group at once has the disputed memo held for review, not served.
The firewall is deterministic Python that needs no model at all, and the answer path is swappable by one environment variable: Anthropic, OpenAI, Gemini, or Ollama. Set LLM_PROVIDER=ollama for air-gapped sovereign deployment and nothing, not one token, leaves the box. The demo itself runs offline with no API key, and the eval scoreboard never calls an LLM.
Every query appends a record to a tamper-evident SHA-256 hash chain: who asked, the resolved permission set, what was served, what was withheld and why, and which model answered. It exports as JSON and is generated inside your VPC. It is the retrieval-access evidence record an EU AI Act Article 50 file asks for, not a compliance certification.
A runnable demo that proves the mechanism. The identity provider is a synthetic Azure-AD/SCIM-shaped JSON fixture, terminations and grant expiries are fixture events, and the vector store runs in-process behind a Qdrant-shaped interface. The policy engine, the eval harness, and the hash-chained audit export are real and run exactly as shown; because the fixture mirrors Azure AD Graph and SCIM interfaces, the documented production path to a live IdP is a config swap, not a rewrite.
The research behind this demo — the architecture, the verification design, and the enterprise blueprint.
The permission layer is the hard part. We build it.
If your team is wrestling with how to point a private model at a corpus governed by years of nested-group inheritance, or with what the EU AI Act's transparency obligations mean for your retrieval logs, we would genuinely like to hear how you are thinking about it. The problem is industry-wide and the answers will be too.