Skip to content

Security: dupeone/accessaware-rag

Security

docs/SECURITY.md

Security

Core invariant

The central security invariant is:

Authorization must happen before vector ranking, keyword matching, neighbor expansion, reranking, prompt construction, and LLM generation.

The model should never receive unauthorized context.

This is the difference between secure RAG and a RAG system that merely asks the model to behave.

Current auth and retrieval security boundary

AccessAware RAG currently uses a server-side TrustedPrincipal as the authorization boundary for endpoints and retrieval.

Current demo identity flow:

X-User-Email
  -> get_current_user()
  -> get_current_principal()
  -> resolve_principal_from_user()
  -> TrustedPrincipal
  -> endpoint and retrieval authorization

Important security properties:

  • Endpoint authorization should depend on TrustedPrincipal, not directly on raw X-User-Email.
  • Demo header authentication is accepted only when AUTH_MODE=demo and DEMO_AUTH_ENABLED=true.
  • Non-demo auth modes must not silently fall back to demo header authentication.
  • Document listing, document detail, cleanup, upload/delete controls, audit access, vector ask, and RAG ask use TrustedPrincipal.
  • Document detail access enforces both classification and grants, preventing direct-ID access to grant-protected documents.
  • Authorized retrieval applies classification and grant filters before vector ranking, keyword candidate selection, reranking, prompt construction, and model context construction.
  • The model should never receive unauthorized chunks.

Current proof points:

  • Unit tests cover principal construction, clearance ordering, access-control helpers, demo auth guard behavior, and retrieval authorization ordering.
  • Smoke tests verify document visibility and RAG behavior across public, internal, restricted, and confidential users.
  • Rich-demo evals verify allowed paths, denied paths, and unauthorized high-similarity questions for benefits, Northwind, and executive-risk documents.

Threat model

Risk Description Control
Cross-user data leakage A user asks a question and semantically similar restricted documents are retrieved. Apply authorization before retrieval and ranking.
Prompt injection Retrieved text tries to override instructions or reveal data. Retrieve only authorized context; require grounded answers.
Over-broad clearance A user has clearance but no business need for a document. Add group/document grants as a need-to-know layer.
Sensitive audit logs Logs accidentally store prompts, answers, chunks, PHI, or secrets. Log safe metadata only.
External provider exposure Authorized sensitive chunks are sent to an external model. Provider-policy metadata, decision service, upload-time embedding gate, RAG answer-generation gate, observe/enforce modes, and audit; future routing and private/local model options.

Access model

Access is based on:

  • user identity
  • user clearance level
  • document classification
  • user group membership
  • document-level grants

Classification ladder:

public -> internal -> restricted -> confidential

A user's clearance allows access to that level and lower levels:

public user       -> public
internal user     -> public, internal
restricted user   -> public, internal, restricted
confidential user -> public, internal, restricted, confidential

Grant model

Classification alone is not enough.

A restricted user should not automatically see every restricted document. They should only see restricted documents they have a business reason to access.

Current grant rule:

User can access a document if:

1. user clearance allows the document classification

AND

2. either:
   - the document has no grants
   - the document is directly granted to the user
   - the document is granted to one of the user's groups
   - the user is a confidential prototype admin

Important design decision:

Grants do not bypass classification.

A grant is not a magic allow. If an internal user is granted to a confidential document, classification should still deny access.

No-grant behavior

Current prototype rule:

no grants = open within classification
grants exist = restricted audience within classification

This keeps simple demo documents usable without requiring every document to have grants.

For stricter production environments, the rule can become:

every non-public document requires an explicit grant

Confidential prototype admin behavior

Current prototype behavior:

confidential clearance = view-all demo admin

This is useful for local demos and smoke tests.

Production should separate:

  • clearance level
  • admin role
  • break-glass access
  • audit reviewer role

In production, a confidential user should not automatically bypass need-to-know grants.

Safe retrieval order

Correct order:

resolve demo/local identity when enabled
  -> build TrustedPrincipal
  -> derive allowed classifications from TrustedPrincipal
  -> use TrustedPrincipal group memberships
  -> filter authorized documents/chunks
  -> perform vector ranking over authorized candidates only
  -> add authorized keyword candidates only
  -> expand neighbors inside authorized documents
  -> rerank authorized chunks
  -> build context from authorized chunks only
  -> evaluate provider/data-egress policy for answer_generation
  -> send authorized context to model only when policy mode allows it
  -> audit safe metadata, including provider-policy decision fields

Unsafe order:

retrieve top vector matches from all documents
  -> send to model
  -> ask model not to reveal unauthorized content

The unsafe order gives the model access to data the user should not see.

Neighbor expansion safety

Neighbor expansion improves answer quality by adding adjacent chunks from the same document.

Security rule:

seed chunk must be authorized
neighbor chunks must belong to the same authorized document

Neighbor expansion must not jump into unauthorized documents.

Reranking safety

Reranking should operate only on authorized candidates.

Current model:

authorized vector candidates
+ authorized keyword candidates
+ authorized neighboring chunks
-> heuristic reranking

Future model-based rerankers must follow provider policy. Sensitive or PHI-containing chunks should not be sent to an external reranking service unless explicitly allowed.

Audit logging

Audit logging proves that the system enforced authorization and operated safely.

The goal is not to store everything. The goal is to record enough metadata to understand what happened without turning logs into a sensitive data store.

Useful audit metadata:

Metadata Why it helps
event_type Classifies the action.
user_email / user_id Ties event to user.
route Shows which endpoint was used.
status Success, denied, or error.
result_count Shows retrieval/listing size.
source_filter Shows requested corpus/source.
allowed_classifications Shows classification scope.
source_document_ids Shows contributing docs without logging content.
source_classifications Confirms classification boundaries.
top_chunk_ids Supports debugging without chunk text.
provider / embedding_model / answer_model Tracks model/provider usage.
provider_policy_mode Shows whether provider policy ran in off, observe, or enforce mode.
ai_provider_mode Shows the configured provider category such as external, enterprise, or local.
provider_policy_operation Shows the operation being evaluated, such as embedding or answer generation.
provider_policy_allowed Shows whether the retrieved authorized context would be allowed for that provider/operation.
provider_policy_reasons Shows policy reasons such as confidential_external_ai_blocked.
provider_policy_document_ids Identifies affected documents without logging content.
retrieval_limit Shows context-size control.
access_control Confirms classification/grants mode.
grant_filter_mode Shows enforced vs prototype bypass behavior.
denied_reason Supports security review.

Avoid logging:

  • full questions when sensitive policy says not to
  • generated answers
  • retrieved chunk text
  • full document text
  • embeddings
  • PHI/PII
  • secrets
  • confidential raw details

Implemented audit event categories include:

  • document upload succeeded
  • vector question asked
  • RAG question asked
  • cleanup blocked/succeeded
  • access denied
  • audit events access denied
  • audit events listed / retrieved

Potential future event categories:

  • document listed
  • document detail accessed
  • grant changed
  • provider policy enforced block
  • redaction applied
  • model-call policy decision

Audit listing endpoint

The audit listing endpoint is confidential/admin-only in the prototype.

Example usage:

GET /audit-events?limit=20
GET /audit-events?event_type=RAG_QUESTION_ASKED&limit=10

Rules:

  • require X-User-Email
  • allow confidential/admin user only
  • return newest events first
  • support safe filters such as limit and event_type
  • do not expose anything more sensitive than the audit rows already contain

Provider / PHI boundary

Access control answers:

Who is allowed to retrieve this content?

Provider policy answers:

Where is this content allowed to be processed?

For regulated, PHI-capable, or highly sensitive use, provider calls are data egress events. This includes embedding, reranking, and answer generation.

Current implemented foundation:

Control Status
contains_phi document flag Implemented.
external_ai_approved document flag Implemented.
requires_local_processing document flag Implemented.
Provider modes: external, enterprise, local Implemented in policy service.
Operations: embedding, answer generation, reranking Implemented in policy service.
Provider-policy tests Implemented.
Upload/list/detail provider metadata Implemented.
Upload audit metadata Implemented.
RAG observe-mode provider-policy audit Implemented.
Upload-time embedding enforcement Implemented.
RAG answer-generation enforcement Implemented.
Provider routing Future work.
Local/private model path Future work.

Current provider-policy flows:

upload-time embedding
  -> evaluate provider policy from declared document metadata with operation=embedding
  -> observe mode audits and continues
  -> enforce mode blocks before file read, extraction, chunking, embedding, or storage

RAG answer generation
  -> authorized retrieval
  -> dedupe source documents
  -> evaluate provider policy for configured ai_provider_mode and operation=answer_generation
  -> observe mode audits and answers normally
  -> enforce mode returns safe fallback without calling the answer model

Observed confidential example:

provider_policy_mode=observe
ai_provider_mode=external
provider_policy_operation=answer_generation
provider_policy_allowed=false
provider_policy_reasons=confidential_external_ai_blocked
provider_policy_document_ids=27

Important distinction:

A user can be authorized to retrieve a document while the document is still not approved for external AI processing.

Future production work should add:

  • provider routing for external|enterprise|local
  • local/private embedding and answer-generation implementations
  • reranker provider policy checks
  • local/private model routing
  • retrieval-only mode
  • redaction/de-identification before model calls when required
  • explicit provider-policy blocked audit events

Even with upload-time embedding and answer-generation enforcement, the project should not be described as PHI-ready until local/private providers, redaction/de-identification, production authentication, and compliance validation exist.

Security limitations

Current limitations to avoid overclaiming:

  • prototype identity via gated X-User-Email demo auth, not real JWT/OIDC auth
  • confidential user behaves as demo admin
  • no full production-grade ReBAC/Zanzibar model yet
  • provider policy is enforced for upload-time embedding and RAG answer generation, but provider routing is not fully implemented
  • not PHI-ready until local/private model paths, redaction/de-identification, production auth, and compliance validation exist
  • audit safety depends on discipline when adding new event details

There aren't any published security advisories