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

./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.