cd /news/artificial-intelligence/show-hn-warden-authorization-gateway… · home topics artificial-intelligence article
[ARTICLE · art-64754] src=github.com ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

Show HN: Warden – authorization gateway for agentic RAG

A developer released Warden, an open-source authorization gateway for agentic RAG systems that enforces relationship-based, deny-aware, cross-tenant document permissions. The tool uses a three-gate architecture combining a permissive pre-filter with a fail-closed authoritative check to prevent data leaks from prompt injection or stale caches. Warden is built with Python, FastAPI, Postgres with pgvector, and Redis.

read5 min views1 publishedJul 18, 2026
Show HN: Warden – authorization gateway for agentic RAG
Image: source

Permission-aware retrieval and agent-authorization gateway for AI systems.

Warden enforces relationship-based, deny-aware, cross-tenant document permissions

insidethe retrieval path of agentic RAG systems — behind a fail-closed security boundary, with agent-context revalidation and a tamper-evident audit trail.

Every existing tool answers "can user U read document D?" None of them answer "what should this agent be allowed to retrieve, keep in context, and cite — right now?"

The two obvious designs both fail.

Post-filter(retrieve top-K, then check permissions) is safe but** recall collapses under selectivity**. If a principal is authorized on 1% of the corpus, top-50 by pure similarity contains ~0.5 authorized docs in expectation.Pre-filter by expanded ID list(SpiceDB.LookupResources

,OpenFGA.ListObjects

) preserves recall but isO(|Authorized(u)|). A firm-wide partner is authorized on 10⁷+ documents. You cannot ship a ten-million-elementIN

clause into an ANN query.

Warden flattens the authorization graph into small capability-label sets that push down into the vector index as an int[]

overlap predicate — O(1) in corpus size — and then treats that filter as a performance optimization only. The security boundary is a separate fail-closed check against the graph itself, on the small candidate set, right before anything enters the model's context.

    agent tool call: retrieve(query)         ← principal is bound server-side to the session
              │                                (NEVER a model-supplied argument)
              ▼
   ┌─ GATE 1 · PRE-FILTER ────────────────────────────────────┐  performance
   │  L(u), B(u) from Redis  [may be stale — permissive only] │
   │  ANN search inside org partition, predicate pushed down: │
   │      acl_labels && L(u)  AND NOT (barrier_tags && B(u))  │
   │  over-fetch K' = 1.5·K                                   │
   └───────────────────────────┬──────────────────────────────┘
                               ▼ K' candidates
   ┌─ GATE 2 · AUTHORITATIVE CHECK ───────────────────────────┐  ← THE SECURITY BOUNDARY
   │  check(u, read, d) against the tuple graph. FAIL-CLOSED. │
   │  deny > allow. expiry enforced. audit row + reason_path. │
   └───────────────────────────┬──────────────────────────────┘
                               ▼ authorized top-K → LLM context
   ┌─ GATE 3 · SESSION REVALIDATION ──────────────────────────┐  temporal
   │  before EVERY model call: re-check all context doc refs  │
   │  evict revoked → inject "[N sources removed]" → replan   │
   │  before final answer: re-check every citation            │
   └──────────────────────────────────────────────────────────┘

Gate 1 is an optimization; Gate 2 is the boundary. A stale cache, a bad label, a pgvector quirk — none can leak, because Gate 2 re-checks the graph. Gate 1 exists so Gate 2 is cheap. Gate 2 exists so Gate 1 is allowed to be wrong.— the pre-filter must be aLabelFilter(u) ⊇ Authorized(u)

permissive superset. Thereforestale revocations are safe(Gate 2 catches them) and** stale grants silently destroy recall**(nothing catches them). Grants propagate eagerly; revocations may propagate lazily. This inverts the naive intuition.

Why prompt injection fails against this: the model can influence the query string. It cannot influence who is asking. The principal is bound to the session server-side and is never a tool parameter. Authorization is enforced at the tool boundary, not by the model's good behavior — because model alignment is not a security control.

Layer Choice Why
Language Python 3.11+ FastAPI ecosystem, Hypothesis, LLM SDKs
API FastAPI Typed, async, OpenAPI-native
Storage Postgres 16 + pgvector 0.8+ ReBAC tuples, vectors, audit — one transaction boundary, no distributed consistency to hand-wave
Cache Redis labels:{principal}:{epoch} with write-through invalidation
Vector index pgvector HNSW + GIN on int[]
Filtered ANN with iterative index scan
Testing Hypothesis + pytest Property-based differential tests vs. a reference oracle
Packaging Docker Compose One-command setup
CI GitHub Actions Property tests + 10-scenario suite + make bench on every PR

Pluggable AuthzBackend

protocol ships with two implementations: our native Postgres engine, and an OpenFGA adapter for teams that already run one.

warden/
├── core/
│   ├── algebra.py         # formal permission semantics
│   ├── oracle.py          # brute-force ground truth — DO NOT OPTIMIZE
│   ├── rebac.py           # check() / expand() / ReasonPath
│   ├── barriers.py        # deny layer + tag encoding
│   └── labels.py          # materialization, epochs, Redis cache
├── retrieval/
│   ├── index.py           # pgvector, partitioning
│   └── strategies.py      # exact | iterative | partitioned
├── gateway/
│   ├── gates.py           # 1, 2, 3
│   ├── session.py         # typed context refs
│   ├── audit.py           # hash chain + verify
│   └── api.py             # FastAPI
├── backends/
│   ├── protocol.py        # AuthzBackend
│   ├── postgres.py
│   └── openfga.py
├── agent/                 # minimal real agent loop
├── evals/
│   ├── generators.py      # Hypothesis strategies
│   ├── differential.py    # vs. oracle
│   ├── scenarios/         # the 10 adversarial cases
│   ├── baseline.py        # naive RAG
│   └── bench/             # the 4 tables
├── profiles/legal.yaml
├── demo/
└── docker-compose.yml

Ship in order. Each milestone has open issues linked to it.

# Milestone What ships

W1check()

with reason paths, information barriersW2W3W4W5Stated explicitly because naming what we didn't build is a seniority signal.

Not an authorization engine competing with SpiceDB or OpenFGA. Warden is thegatewaythat composes an authz model with a retrieval path and an agent lifecycle. Native engine so it works standalone; adapter so it doesn't have to.Not a vector database. pgvector is an implementation detail.Not production-hardened. Single-node, synthetic benchmarks. Numbers will say so plainly.Not a hallucination checker. Citation stripping here is anaccess-controlmechanism, not a correctness one.

docker-compose up          # Postgres + pgvector + Redis + API + seeded demo corpus
make test                  # property tests + 10 scenarios
make bench                 # four benchmark tables (smoke scale)
make demo                  # split-screen UI at http://localhost:3000

TBD.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @warden 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-warden-autho…] indexed:0 read:5min 2026-07-18 ·