Sections in this lesson
Secure RAG: Access & Ingestion
A document belongs to a tenant and requires a trusted approval decision before retrieval.
Reviewed: · Content owner: Interview Preparator
What you will learn
- Approval starts at ingestion
- Carry scope through caches and citations
- Test what is excluded
Before you start
The flow
- 1.Identify scope
- 2.Inspect evidence
- 3.Apply host control
- 4.Run negative cases
- 5.Compare benign behavior
- 6.Review remaining risks
Approval starts at ingestion
A document belongs to a tenant and requires a trusted approval decision before retrieval. Content cannot approve itself. Preserve source identity, ingestion provenance and a review state; missing approval should not silently mean approved.
The Java lab now seeds explicit approved metadata and applies tenant plus approval filtering in pgvector. Integration tests insert unapproved and missing-approval documents and verify that neither becomes evidence.
Carry scope through caches and citations
Authorization is not only a query predicate. Cache keys need tenant/user/corpus scope, and cached evidence still requires current access checks after revocation or deletion. A cited source ID cannot grant access to its document.
The Node fixture also checks reader membership, deletion and expiry. These are teaching fields separate from the Java tenant-level demo; the Java service is not presented as a complete per-user ACL implementation.
Test what is excluded
Cover mixed selections, foreign tenants, removed documents and stale cache values. A source selector may only intersect already authorized retrieval candidates. Do not convert it into an arbitrary document fetch.
Trusted ingestion does not establish that a document is factually true or free of malicious instructions. Keep access controls, injection containment and claim verification as different layers with separate evidence.
Try it
// Closed-world fact fixtures only. Equality of structured facts is NOT an NLI judge.const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);export function authorizedSources(sources, scope, now) { if (!object(scope) || typeof scope.tenant !== 'string' || typeof scope.user !== 'string' || !Number.isFinite(now)) throw new Error('Invalid trusted scope/time'); return sources.filter(source => source.tenant === scope.tenant && source.approved === true && !source.deleted && source.expiresAt > now && source.readers.includes(scope.user));}export function verifyClaims(claims, sources, scope, now) { if (!Array.isArray(claims) || claims.length > 20) throw new Error('Invalid claims'); const evidence = authorizedSources(sources, scope, now); return claims.map(claim => { if (!object(claim) || Object.keys(claim).sort().join(',') !== 'key,sourceId,value' || ![claim.key,claim.sourceId,claim.value].every(value => typeof value === 'string' && value.length > 0 && value.length <= 200)) throw new Error('Invalid structured claim'); const source = evidence.find(item => item.id === claim.sourceId); const value = source?.facts[claim.key]; return { ...claim, label: value === undefined ? 'INSUFFICIENT_EVIDENCE' : value === claim.value ? 'SUPPORTED' : 'CONTRADICTED' }; });}export function answerPolicy(claims, sources, scope, now) { const labels = verifyClaims(claims,sources,scope,now); return { status:labels.length > 0 && labels.every(item => item.label === 'SUPPORTED') ? 'ANSWER' : 'ABSTAIN', claims:labels };}export function retrievalRecall(relevantIds, retrievedIds) { if (!relevantIds.length) return null; return [...new Set(relevantIds)].filter(id => retrievedIds.includes(id)).length / new Set(relevantIds).size;}export function judgeAgreement(human, judge) { if (human.length !== judge.length) throw new Error('Unpaired annotations'); return human.length ? human.filter((label,index) => label === judge[index]).length / human.length : null;}Run npm run examples:security and npm run eval:security. This source is a deterministic teaching fixture; it does not prove live model safety, NLI, production auth or OS/network isolation.
Interview questions
Who approves an imported document?
The Java lab now seeds explicit approved metadata and applies tenant plus approval filtering in pgvector. Integration tests insert unapproved and missing-approval documents and verify that neither becomes evidence.
Why must a cached answer be reauthorized?
The Node fixture also checks reader membership, deletion and expiry. These are teaching fields separate from the Java tenant-level demo; the Java service is not presented as a complete per-user ACL implementation.
Does approved ingestion prove factual truth?
Trusted ingestion does not establish that a document is factually true or free of malicious instructions. Keep access controls, injection containment and claim verification as different layers with separate evidence.
Practice
Extend one negative scenario and its authorized positive counterexample for Secure RAG: Access & Ingestion.
Check your solution
- State the trusted input and effect boundary.
- Assert the expected status and observed effect.
- Report coverage and limitations without claiming production readiness.
Official references
Continue learning
Category sequence
AI Security
Lesson 5 / 14
Was this lesson useful?
Change notes: 2026-10-31: security/reliability curriculum and source-bound fixture.