Add semantic guardrail layer for prompt-injection pre-check

Extends the regex-only pre-check into three stages: regex scan, then
embedding-similarity search against known injection examples, and only
if that score clears a threshold, an LLM judge confirms intent before
blocking. Catches paraphrased injection attempts the fixed regex
patterns miss without paying for an LLM call on every query.

Validated end-to-end against a real Anthropic API key and a live
Qdrant instance: the new path correctly blocked a paraphrased
injection (audit log confirms rule_id: injection.semantic_llm_judge)
while a benign near-miss passed through without ever reaching the LLM
judge. Also documents two reliability issues found while testing with
claude-haiku-4-5 (a non-deterministic policy verdict and a forced
tool-call loop that can end without calling any tool) in
docs/SAFETY_WRITEUP.md section 6 -- unrelated to this change, but
worth recording since they were found in the same pass.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
msjid
2026-09-19 17:56:03 +02:00
co-authored by Claude Sonnet 5
parent a72be63574
commit ae93c776fa
12 changed files with 372 additions and 37 deletions
+10
View File
@@ -24,6 +24,16 @@ pub struct RetrievalOutput {
pub extracted_reference: Option<String>,
}
/// Structured output of the LLM injection judge (see
/// `guardrails/injection_judge.rs`), called only when the semantic
/// guardrail's embedding-similarity pre-filter flags a query as close
/// enough to a known injection example to be worth a second opinion.
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct InjectionVerdict {
pub is_injection: bool,
pub reasoning: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct PolicyVerdict {
pub compliant: bool,