Authorize retrieval before evidence reaches the model
Implement a deny-by-default evidence policy for a shared support index. Check tenant membership, object access and the draft recipient before context construction, then handle stale permissions, cached answers and in-flight work explicitly.
24 MIN
By AISecurityInterviews · Updated
TL;DR: Authorize evidence before it reaches a model, log or recipient outside its permitted boundary. Scope candidate retrieval, enforce current object permissions and distinguish staff research from a customer-facing draft. Tenant/user cache keys help separate users but do not keep cached permissions current.
Where you are. Module two, lesson one. You will turn the case's permission table into an executable policy and a revocation test matrix.
Decide whose task this is
Mina's customer chat and Aria's internal investigation have different evidence scopes. A third task, drafting a reply to Mina, needs evidence suitable for that recipient. Treat the task type as an application policy choice. The model cannot promote a customer answer into a staff investigation by proposing a different label.
Derive the actor from verified authentication, then resolve current membership and object grants. A tenant selector from a request may identify a desired workspace, but the service must confirm the actor belongs to it. A signed token can still carry stale role information; choose how role changes reach the authorizer and what happens while that service is unavailable.
An application service credential is not intrinsically wrong. It becomes dangerous when a caller can use its broad reach without mandatory user and task checks. Prefer storage constraints and narrow service permissions where available, then enforce the remaining object rules in a shared access layer. A delegated user token still needs the same business-policy decisions.
Scope retrieval and enforce the final evidence gate
Use a tenant-scoped query to reduce candidates and avoid retrieving irrelevant private material. Apply object-level rules before unauthorized text reaches a model, reranker, trace or caller. If a search engine's permission metadata can lag the source, either give that metadata an adequate freshness guarantee or check current authoritative permissions before exposure.
Post-filtering inside a properly isolated, mandatory authorization service can enforce a boundary. It is not automatically a leak. Its disadvantages may include sensitive candidates entering more infrastructure, poor recall and bypass risk if some callers can omit the filter. Pre-filtering is useful but not sufficient when its policy is stale or wrong. Review the actual data path rather than treating the filter's name as a security property.
Verified actor
Resolve current membership
Scoped candidates
Tenant and task constraints
Evidence gate
Current object and recipient policy
Permitted context
Dispatch under processor policy
Separate selection and permission
Relevance selects candidates. The evidence gate decides which records may cross into this task’s context.
A per-tenant namespace also helps only if callers cannot choose an arbitrary namespace or use a credential that bypasses the intended routing. “Separate index” is a design detail; the enforced boundary is who may query which data.
Run a small policy model
This offline example models four records and current membership. It does not implement authentication, vector ranking, storage isolation or distributed revocation. The document reader lists stand for authoritative object grants. For a customer draft, both the staff actor and the intended recipient must be allowed to read every selected record. A real product may have a separate disclosure policy; represent that explicitly instead of assuming a read grant covers delivery.
from dataclasses import dataclass
@dataclass(frozen=True)
class Actor:
tenant: str
user: str
MEMBERS = {"alder": {"mina", "noor", "aria"}, "birch": {"eli"}}
DOCS = [
dict(id="help", tenant="alder", published=True, readers=set()),
dict(id="mina-ticket", tenant="alder", published=False,
readers={"mina", "aria"}),
dict(id="noor-ticket", tenant="alder", published=False,
readers={"noor", "aria"}),
dict(id="birch-ticket", tenant="birch", published=False,
readers={"eli"}),
]
def may_read(actor, doc):
if actor.user not in MEMBERS.get(actor.tenant, set()):
return False
if doc["tenant"] != actor.tenant:
return False
return doc["published"] or actor.user in doc["readers"]
def evidence(actor, recipient=None):
# A list replaces candidate retrieval; authorization precedes disclosure.
return [doc["id"] for doc in DOCS if may_read(actor, doc)
and (recipient is None or may_read(recipient, doc))]
mina = Actor("alder", "mina")
aria = Actor("alder", "aria")
print(evidence(mina)) # => ['help', 'mina-ticket']
print(evidence(aria)) # => ['help', 'mina-ticket', 'noor-ticket']
print(evidence(aria, mina)) # => ['help', 'mina-ticket']
MEMBERS["alder"].remove("aria")
print(evidence(aria, mina)) # => []
Run it in an isolated local interpreter. Then add an unpublished staff-only note and an unknown actor. Predict the result before changing the fixture. The note must not enter Mina's customer draft, and the unknown actor must receive no records. These are behavioral expectations, not a claim that this miniature function is production-ready.
The OWASP authorization cheat sheet is the reference for default denial and checking object permissions on each request. Our recipient check adds a policy specific to the support workflow.
Revocation has a timeline
Consider three moments: evidence selected, model request sent, answer delivered. If access is revoked between selection and delivery, a final permission check can block delivery but cannot undo disclosure to a processor that already received the prompt. Define which revocation guarantees the product requires at each boundary. Sensitive workflows may need shorter-lived work, current checks before dispatch and cancellation of queued results when policy changes.
Test a missing or unavailable authorizer as well as a denied record. Falling back to an old permissive cache entry converts an outage into a confidentiality failure. An acceptable degraded mode for this case is published-help-only answers, if that mode has a separate verified access path; otherwise return an unavailable result.
For caches, include tenant, actor, task, recipient and relevant policy/content versions where the output depends on them. Reauthorize or invalidate when grants change. A long-lived cache with a detailed key can still serve an obsolete answer. Revocation must also cover conversation summaries, citation previews, exports and background jobs.
Do this before moving on
Build a table with six cases: another tenant, another customer in the same tenant, an unpublished article, a revoked staff grant, an old cached answer and a queued draft whose recipient changed. For each, record the expected evidence set and the last permissible delivery decision.
Use the example for the first four. For the cache and queue cases, write the timeline and identify what a pure function cannot test. A complete answer names the integration test and the component that owns cancellation or reauthorization. Test only synthetic records in a system you own or are authorized to assess.
Go deeper
- Broken access control explains the object-level rule behind the evidence gate.
- RAG document-level access changes the permissions model and tests your retrieval design.
- RAG security adds source integrity and poisoning to the access-control problem.
- A chatbot showed other users' data prepares the investigation when an isolation check fails.
Key takeaways
- Actor, task and recipient determine which evidence belongs in a context.
- Search scoping and current object authorization solve different problems.
- Cache separation does not establish permission freshness.
- State revocation guarantees separately for selection, processor dispatch and final delivery.
Check yourself
Say or write your answer first, then reveal. Explaining it from memory, in your own words, is the skill an interviewer is checking.
1A search service retrieves candidates internally, then applies an unavoidable current permission check before any text reaches a model, trace or caller. Is post-filtering alone evidence of a leak?
2Aria’s grant is revoked after a prompt was sent but before its draft is delivered. What can a final access check accomplish?
3The response-cache key includes tenant and user. What must the revocation test still verify?
Sign in to track which lessons you have finished.