sentinel / docs /v2_flow.md
samarthmishra46's picture
Sentinel V2 β€” HF deploy snapshot (full stack, DeBERTa on)
1788dab
|
Raw
History Blame Contribute Delete
16.7 kB
# Sentinel β€” how a request flows
Every stage, in order, with what it checks and what it can return. Cheapest checks run
first and a **STOP short-circuits the rest**, so the expensive semantic work only ever sees
prompts that survived everything cheap.
`β˜…NEW` marks what V2 added. All new tiers ship **switched off** behind an env flag.
---
## The whole path
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ USER TYPES A PROMPT β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PEP INGRESS β”‚
β”‚ POST /v1/chat β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–Ό
╔══════════════════════════════════════════════════════════════════════════╗
β•‘ INPUT PIPELINE (cheapest first) β•‘
╠══════════════════════════════════════════════════════════════════════════╣
β•‘ β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 1 Β· NORMALIZE <1ms β”‚ whitespace, zero-width, homoglyphs β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β•‘
β•‘ β–Ό β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 2 Β· IDENTITY <1ms β”‚ role/tenant/owned_services from β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ EIM TOKEN β€” never from prompt text β•‘
β•‘ β–Ό β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 3 Β· CEDAR AUTHZ O(1) β”œβ”€β”€β”€β”€ not permitted ──► STOP R-AUTH β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β•‘
β•‘ β–Ό permitted β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 4 Β· SECRETS regex β”œβ”€β”€β”€β”€ hit ────────────► STOP R-07 β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ db URIs, AWS keys, tokens β•‘
β•‘ β–Ό β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 5 Β· INJECTION (phrases) β”œβ”€β”€β”€β”€ hit ────────────► STOP R-06 β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ~40 literal jailbreak phrases β•‘
β•‘ β–Ό β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 6 Β· PII regex β”œβ”€β”€β”€β”€ hit ────────────► STOP R-01 β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ TFN passport Medicare licence β•‘
β•‘ β–Ό name+DOB address PAN Aadhaar β•‘
β•‘ IBAN SWIFT SSN card email β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 7 Β· COMPLIANCE RULES β”œβ”€β”€β”€β”€ hit ────────────► STOP / ESCALATE β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ verb + object must BOTH match β•‘
β•‘ β–Ό R-02 R-03 R-04 R-05 R-09 β•‘
β•‘ ╔═══════════════════════════════╗ β•‘
β•‘ β•‘ 8 Β· SEMANTIC LAYER β˜…NEW β•‘ ~40ms Β· 52ms p95 β•‘
β•‘ β•‘ (expanded below) ╠──── hit ────────────► STOP / ESCALATE β•‘
β•‘ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β”¬β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β•‘
β•‘ β–Ό β•‘
β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
β•‘ β”‚ 9 Β· DESTRUCTIVE OPS β”œβ”€β”€β”€β”€ hit ────────────► ESCALATE R-21 β•‘
β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ delete/drop + customers/records β•‘
β•‘ β–Ό β•‘
β•‘ ╔═══════════════════════════════╗ β•‘
β•‘ β•‘ 10 Β· BEHAVIOUR β˜…NEW β•‘ looks ACROSS requests: β•‘
β•‘ β•‘ ╠──── anomaly ────────► ESCALATE R-22 β•‘
β•‘ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β”¬β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• queries/hr Β· distinct customers Β· β•‘
β•‘ β”‚ off-owned svc Β· off-hours Β· streak β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β”Όβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ COMBINE β”‚ strictest wins = max()
β”‚ ALLOW=0 ESC=1 STOP=2β”‚ empty set β†’ ESCALATE (fail-closed)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β–Ό β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”
β”‚ STOP β”‚ β”‚ESCALATE β”‚ β”‚ ALLOW β”‚
β””β”€β”€β”€β”¬β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜
β”‚ β”‚ β–Ό
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚ BACK-END AI β”‚
β”‚ β”‚ β”‚ generate(prompt, β”‚
β”‚ β”‚ β”‚ ctx) β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ β–Ό
β”‚ β”‚ ╔══════════════════════════════════════╗
β”‚ β”‚ β•‘ OUTPUT SCANNER β•‘
β”‚ β”‚ β•‘ O1 normalize β•‘
β”‚ β”‚ β•‘ O2 PII / secrets leak β•‘
β”‚ β”‚ β•‘ O3 unsafe code (bypass, exploit) β•‘
β”‚ β”‚ β•‘ O4 alignment (sys-prompt, DAN) β•‘
β”‚ β”‚ β•‘ O5 EXCHANGE β˜…NEW answer vs prompt β•‘
β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β”¬β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β–Ό β–Ό β–Ό
β”‚ β”‚ BLOCK REDACT PASS
β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ β”‚ β–Ό
β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚ β”‚ ANSWER DELIVEREDβ”‚
β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–Ό β–Ό β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ AUDIT LOG β”‚
β”‚ decision Β· rule_triggered Β· policy_triggeredβ”‚
β”‚ reason Β· prompt_hash(sha256) Β· user_id β”‚
β”‚ role Β· service Β· latency_ms Β· signals β”‚
β”‚ policy_version Β· timestamp Β· request_id β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό (ESCALATE only)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ HUMAN REVIEWER ──► labelled example β”‚
β”‚ β–² β”‚ β”‚
β”‚ β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Stage 8 │◄────── RETRAIN (39KB) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β–²β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ catalog.yaml ──► generate ──► mutate ──► spot-check
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
THE FLYWHEEL: rules become training data
```
**Fail-closed everywhere.** Unknown user β†’ STOP. A stage throws β†’ ESCALATE. No verdicts at
all β†’ ESCALATE. Audit unreachable β†’ ESCALATE. Silence is never treated as approval.
---
## Stage 8 expanded β€” embed once, use twice
The expensive part is turning the prompt into numbers. Do it **once**, cache it, and both
consumers read the same vector β€” which is why the second one is nearly free.
```
prompt survived stages 1-7
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ EMBED ONCE β”‚
β”‚ MiniLM β†’ 384 numbers Β· memoized β”‚ ~40ms
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ (same cached vector)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ └───────────┐
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ kNN SIMILARITY β”‚ β”‚ INTENT CLASSIFIER β”‚
β”‚ vs 584 attacks β”‚ β”‚ softmax(WΒ·x+b) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ ~0ms extra
β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β–Ό β–Ό β–Ό β–Ό β–Ό β–Ό
β‰₯0.80 0.72-0.80 <0.72 β‰₯0.70 0.45-0.70 benign
β”‚ β”‚ β”‚ β”‚ β”‚ <0.45
β–Ό β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β–Ό β–Ό β–Ό
STOP β”‚ rule's own ESCALATE pass
cites β”‚ level: (softened)
attack β”‚ R-02/03/09
ID β–Ό β†’ STOP
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” R-05
β”‚ DeBERTa RECHECK β”‚ β†’ ESCALATE
β”‚ ON by default ~340ms β”‚
β”‚ β‰₯0.90 STOP β”‚
β”‚ β‰₯0.50 ESCALATE β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
**Why the recheck.** Similarity only recognises paraphrases of attacks *already in the
bank*, so "far from every known attack" is not evidence of being benign β€” it is the gap
novel wording walks through. Everything the kNN tier does not STOP outright, band or
apparent-pass alike, gets a second opinion from DeBERTa. Only a tier-1 STOP skips it, so
in practice nearly every surviving prompt pays the ~340ms: recall bought with latency.
**Ceiling rule.** Similarity says *which* attack; the catalog says *how strict* it is. A
perfect 1.00 match to an ESCALATE-class rule (R-05 bulk, R-08 cross-org) still only
escalates β€” never STOP.
**Why cite a neighbour.** A match reports *"0.94 similar to known attack RT-04"* β€” a sentence
an auditor can follow. A bare confidence score of 0.87 explains nothing.
**New attack on Monday** β†’ add one bank entry β†’ protected that afternoon. No retraining, no
redeploy.
---
## The three verdicts
| Verdict | Value | What happens | Does the AI see the prompt? |
|---|---|---|---|
| ALLOW | 0 | passes through to the assistant | yes |
| ESCALATE | 1 | held for a human; becomes a labelled example | not yet |
| STOP | 2 | refused, rule + policy cited | never |
Higher number = stricter, so combining is a plain `max()` and can't be got wrong.
---
## Stage reference
| # | Stage | Catches | Emits | Cost |
|---|---|---|---|---|
| 1 | normalize | obfuscation | β€” | <1ms |
| 2 | identity | β€” | β€” | <1ms |
| 3 | Cedar authz | unpermitted identity | STOP R-AUTH | O(1) bitmask |
| 4 | secrets | connection strings, AWS keys, tokens | STOP R-07 | regex |
| 5 | injection (phrase) | literal jailbreak phrases | STOP R-06 | Aho-Corasick |
| 6 | PII | AU IDs + PAN, Aadhaar, IBAN, SWIFT, SSN, card, email | STOP R-01 | regex |
| 7 | compliance rules | SMR/TTR, bypass, attack, bulk, audit-manip | STOP/ESCALATE | two-part match |
| 8 | **semantic β˜…** | paraphrased attacks | STOP/ESCALATE | ~40ms, 52ms p95 |
| 9 | destructive ops | delete/drop + customer objects | ESCALATE R-21 | regex |
| 10 | **behaviour β˜…** | patterns across requests | ESCALATE R-22 | in-memory |
Order is load-bearing: a pasted password STOPs at stage 4 in microseconds and never reaches
the 40ms semantic layer.
---
## Running it
```bash
./run_v2.sh demo # see it catch bulk assembly + a paraphrased bypass
./run_v2.sh gate # 13-prompt red-team gate, all tiers on
./run_v2.sh eval # the adversarial numbers
./run_v2.sh serve # API + web UI on localhost:8000
./run_v2.sh test # full suite (tiers off, like CI)
```
Flags: `KNN_ENABLED` Β· `INTENT_ML_ENABLED` Β· `BEHAVIOUR_ENABLED` default **false**;
`ML_DETECTOR_ENABLED` defaults **true** (the DeBERTa recheck; set it false for the fast
deterministic path β€” the deploy image does). Measured results in [v2_eval_results.md](v2_eval_results.md).