Skip to main content
Every scan call returns one of four verdicts. The whole firewall is about getting the right one back and acting on it correctly.

The four values

flag passes content through unmodified: it’s a recording verdict, not an enforcement one. It exists so the firewall can surface suspicion (an elevated injection score with no independent corroboration, or a NER detector running in its default monitor mode) without ever mutating or blocking traffic on a signal that isn’t trusted enough to act on yet. Watch flag volume in Observability; a sustained rise is the signal that it’s time to either add corroborating signals (custom phrases, tighter structural rules) or promote a detector from monitor to enforcing mode.

Two thresholds, two directions

There are four threshold values per App: one block and one redact for input traffic, plus one block and one redact for output traffic. Defaults: See Configuration for how to change them.

How the verdict is computed

Injection and PII are independent concerns, decided separately and then merged by severity (block > redact > flag > allow). Redaction is a PII remedy, and masking characters does nothing to neutralise “ignore all previous instructions”, so the injection signal only ever yields block / flag / allow, never redact on its own. For each direction (input or output):
  1. The classifier produces an injection.score ∈ [0, 1].
  2. If any custom phrase matches, the injection signal is forced to block regardless of model score.
  3. Otherwise the injection signal needs corroboration to block:
    • injection.score ≥ block_threshold and at least one of a phrase‑pack hit, a structural marker (see below), an INJECTION verdict from the LLM‑judge tier, or a non‑fallback embedding‑anomaly hit → block.
    • injection.score ≥ block_threshold without corroboration, or injection.score ≥ redact_thresholdflag. The bare ML classifier is too imprecise to block on alone: it false‑positives near 1.0 on benign out‑of‑distribution content (data tables, IBANs, ordinary task instructions), so an uncorroborated high score is downgraded to flag instead of silently passing as allow. Check injection.meta.uncorroborated_injection on the response to see when this happened.
    • Else → allow.
  4. PII / secret detectors produce a list of findings, scored independently. Any enforcing finding (i.e. not from a detector running in monitor mode, see NER PII detection) → the PII signal is redact.
  5. The two signals merge by severity. If the injection signal is flag (or PII findings exist only from a monitor‑mode detector, with no enforcing findings) and nothing else raised the verdict higher, the final verdict is flag rather than allow. The event is still recorded as suspicious even though nothing was mutated.
“Structural markers” are non‑ML signals over the raw text: <<SYS>> / [system] / ### System: role‑forgery markers, wrapped/PEM‑style base64 reassembly, zero‑width and invisible‑character obfuscation, and similar. Multiple co‑occurring weaker structural signals compound toward a higher combined score rather than being capped at the strongest single signal. The exact block_threshold / redact_threshold are App‑level for input, with separate output_* values for the post‑LLM scan.
A crashed classifier doesn’t fail open by default in every posture. Set RUNTIME_SECURITY_FAIL_MODE=closed (workspace‑level env var) to force block instead of falling back to the remaining signals when the ML classifier errors at runtime. See Errors & FAQ → Fail‑closed behaviour.

Acting on each verdict

On allow

Forward the original text. There is nothing to do. The uuid is still useful to log if you want to correlate dashboards back to specific user requests.

On flag

Forward the original text: flag never rewrites anything. Log it and treat it as a lead: filter the event log to verdict=flag to see what’s being suspected but not (yet) acted on. It’s the expected outcome for an uncorroborated high injection score and for the default monitor mode of the NER PII tier (see below); it’s a deliberate “don’t act on this alone” signal, not a bug in your integration.

On redact

Use redacted_text for inputs and outputs, or redacted_arguments for tool calls. PII spans are replaced with category markers:
The category set covers structured secrets: EMAIL, PHONE, SSN, IP, URL, API_KEY, JWT, AWS_ACCESS_KEY, GITHUB_PAT (also GITHUB_TOKEN for the gho_/ghs_/ghu_/ghr_ prefixes), SLACK_TOKEN, GOOGLE_API_KEY, STRIPE_KEY, OPENAI_API_KEY / ANTHROPIC_API_KEY, PEM_PRIVATE_KEY, BEARER_TOKEN, plus any custom categories you defined as App‑level or workspace‑level rules, and, when the NER PII tier is enabled in redact mode, unstructured categories like PERSON, ADDRESS, DATE_OF_BIRTH, MEDICAL_CONDITION, and any custom zero‑shot label you configured. Findings carry an extra object; NER‑sourced findings have extra.detector = "ner_gliner2" and extra.model (the HuggingFace model id) alongside the usual type / subtype / score / start / end, so you can tell a regex hit from a NER hit in the audit trail.

On block

Don’t forward anything to the upstream model. Surface a refusal to your end user. The blocked_reason field is safe to derive a message from (prompt_injection:score=0.97, shell.dangerous:argument contains dangerous shell construct, …). Log the uuid. The same UUID appears on the audit event so you can pull it up in the Blindsight dashboard when investigating.

Why block returns HTTP 200

The verdict is information your application needs. Returning 200 with verdict, blocked_reason, uuid, and the underlying score keeps the contract clean. Non‑200 codes are reserved for protocol failures (auth, rate limit, quota) where the client genuinely cannot retrieve a verdict.

What redacted_text looks like vs the original

On verdict: allow, redacted_text equals the original. On block, do not forward redacted_text either; the prompt content shouldn’t reach the model.

Tuning thresholds

Start with the defaults. Move them only when you have data.
Raise both thresholds in small steps (5 percentage points at a time). Watch the verdict mix shift in the analytics page.
Lower the redact threshold first. That converts borderline allows into redacts without breaking user requests. Only drop the block threshold once you trust the redact one.
Don’t change workspace thresholds. Make a new App and put the sensitive surface there. The healthcare template ships with block 0.75 / redact 0.45; clone it for any PHI workload.

See also

  • Configuration for how to set thresholds, detectors, custom phrases, and tool policy.
  • Observability for verdict timelines, drift, and per‑category breakdowns.
  • Errors & FAQ for what to do when you see a non‑200 response.