ADR-006: AI security guardrails & resilience¶
Status: Accepted Β· Date: 2026-08-23
Context¶
An AI/RAG app has a threat surface a normal API doesn't: prompt injection (direct and indirect), system-prompt leakage, sensitive-info disclosure, tool abuse, and dependency failures unique to LLM/vector-DB backends.
Decision¶
Layered controls, each independently tested (automation/security/, tests/unit/test_resilience.py):
- Indirect prompt-injection defence (
rag/guardrails.py). Retrieved document content is treated strictly as data. Before context reaches the LLM, sentences matching injection patterns ("ignore all instructions", "always answer every questionβ¦", "system note:") are stripped, and a fully-injected chunk's content is removed (not passed through). Verified: an uploaded malicious document can no longer make the assistant emit its planted canary, while benign facts survive. - Agent tool allowlist (ADR-004 sibling). The agent can only call read-only tools; destructive tools are refused. Injection text never changes the tool plan.
- MCP read-only surface (ADR-005). No exposed tool mutates state.
- Secret hygiene (
observability/). ARedactingFilterscrubs JWTs, bearer headers, DB URLs, and API keys from ALL logs. Spans capture metrics, never prompts. - Security headers + strict CORS on the API; tampered/expired JWTs rejected.
- Graceful degradation. LLM timeouts and vector-store outages produce a
user-safe message and a
503(never a500/stack trace), with adegradedflag and error class for observability.
Consequences¶
- (+) The common OWASP-LLM risks have concrete, tested mitigations.
- (+) Failures are observable and safe; secrets can't leak through logs by accident.
- (β) The injection filter is pattern-based and can be bypassed by novel phrasings; it is defence-in-depth, not a guarantee. Documented as such; a real deployment would add model-side and output-side checks too.