Designing Allow, Review and Block Security Decisions
Design allow, review, and block security decisions — why ternary verdicts beat binary flags for high-impact operations and human review.
Binary allow/deny security APIs force a false choice: block too much and users revolt; allow too much and incidents happen. Production AI systems need a ternary model — allow, review, and block — mapped from detector verdicts to application actions with explicit precedence and audit trails.
This guide explains why three states beat boolean flags, how IdenticAPI verdicts map to each action, and how to design review workflows that reduce both false positives and false negatives.
Related: Block vs Review for AI Output, AI Agent Policy Decisions, False Positives vs False Negatives.
Why binary models break down
| Binary approach | Failure mode |
|---|---|
| Block on any signal | Benign security docs, quoted attacks, technical HTML → guardrail fatigue |
| Allow unless certain | Paraphrased injection, subtle PII, borderline phishing → silent incidents |
| "Score > 0.7 = block" | No buffer for ambiguous cases; threshold wars between teams |
Security operations already use quarantine states — email spam folders, WAF challenge pages, fraud holds. LLM products need the same middle state for medium-confidence signals.
IdenticAPI expresses this as:
- Single detectors:
safe/suspicious/unsafe - Unified Guard per-check:
allow/review/block - Aggregated
decisionwith block > review > allow priority
The three actions defined
Allow
Meaning: Proceed with the normal pipeline — call the model, deliver output, execute the tool.
Typical detector mapping: safe / allow with low risk and no blocking categories.
Requirements:
- Downstream controls still apply (sanitization, CSP, authorization)
- Log
request_idand metadata for sampling
Allow is not "trust the content" — it means automated policy permits this step.
Review
Meaning: Hold for human or secondary automated adjudication before proceeding.
Typical detector mapping: suspicious / review, or medium risk with non-blocking categories.
Requirements:
- End users see a neutral holding message — not flagged content
- Queue stores context access-controlled for reviewers
- SLA and escalation paths defined
- Reviewer outcome logged (true positive / false positive) for tuning
Review absorbs ambiguity — the primary false-positive and false-negative mitigation. See AI guardrails false positives.
Block
Meaning: Stop the pipeline; do not call the model, deliver output, or execute the tool.
Typical detector mapping: unsafe / block, high risk, secrets, executable markup, destructive agent actions.
Requirements:
- Static pre-approved fallback message to users
- Do not echo flagged text in errors or client responses
- Log
request_id, verdict, categories — minimize raw content in production logs
Block is for high-confidence harm where exposure is unacceptable.
Verdict mapping reference
Input and output text (injection, PII, output safety)
| Verdict | Risk (typical) | Suggested default | Override when |
|---|---|---|---|
safe | low | Allow | — |
suspicious | medium | Review | High-trust internal tools may allow specific categories |
unsafe | high | Block | Never allow secrets or executable markup to users |
PII nuance:
- Secrets (
unsafe) → almost always block, never redact-and-forward without rotation policy - PII (
suspicious) → review or redact-then-allow per privacy policy
Agent actions
| Verdict | Suggested default |
|---|---|
allow | Execute tool with normal authorization |
review | Queue for human approval (HITL) |
block | Reject proposal; return safe failure to agent loop |
Agent Action Guard evaluates structured tool_name, action, and arguments — not chat prose alone.
Unified Guard aggregation
When multiple checks run in one POST /api/v1/guard call:
{
"decision": "block",
"checks": [
{ "check": "prompt_injection", "verdict": "allow", "risk": "low", "findings": [] },
{ "check": "pii_secrets", "verdict": "block", "risk": "high", "findings": [{ "category": "api_key" }] }
],
"usage_units": 2,
"request_id": "req_abc123"
}
One block check forces decision: block regardless of other results. Your middleware should persist per-check findings for incident analysis.
Decision matrix by finding category
Use findings[].category — not verdict alone:
| Category (illustrative) | Verdict | Action |
|---|---|---|
api_key, private_key, bearer_token | unsafe | Block |
instruction_override | unsafe | Block on public chat; review on internal docs search |
unsafe_html | unsafe | Block before DOM render |
email, phone | suspicious | Review or redact-then-allow |
phishing_pattern | unsafe | Block |
policy_topic_medical | suspicious | Review for regulated products |
Store matrices in version-controlled policy config — not scattered if statements.
Precedence rules
When multiple signals exist in one request:
- Any block → block (secrets beat benign injection allow)
- Else any review → review
- Else → allow
Same precedence as Unified Guard decision aggregation. Apply consistently across input, output, and agent stages.
Anti-pattern: letting the "most permissive" check win because it ran last.
Review queue design
Effective queues include:
| Field | Purpose |
|---|---|
request_id | Trace to scanner |
| User / tenant ID | Authorization for reviewer |
| Surface (chat, RAG, agent) | Context for policy |
findings[].category + reasons | Why it flagged |
| Proposed action (for agents) | Structured tool call |
| SLA timer | Prevent stagnation |
Reviewer actions:
- Approve — deliver or execute (possibly edited)
- Reject — block with template message
- Escalate — security or legal
- Mark false positive — feeds metrics
Users never see pending flagged model text. See moderate AI chatbot responses.
Block workflow essentials
- Return pre-approved fallback — no model echo
- Log correlation IDs
- Optional session abuse counters
- For secrets: trigger rotation runbook
Example fallback:
"I can't process that request. Please rephrase or contact support."
Fail-open vs fail-closed on API errors
Scanner unavailability is not a verdict:
| Policy | Behavior | When |
|---|---|---|
| Fail closed | Block or review queue | High-assurance, regulated, public HTML |
| Fail open | Allow with alert | Low-risk internal prototypes only |
Document explicitly — do not conflate outage with allow verdict. See fail-open vs fail-closed.
Surface-specific policies
One global map rarely fits:
| Surface | Block | Review | Allow bias |
|---|---|---|---|
| Public support chat | unsafe | suspicious | Strict |
| Internal code copilot | unsafe secrets | suspicious injection | Looser on jargon |
| Agent with email tool | unsafe + external send | ambiguous writes | Strict on egress |
| Read-only FAQ | unsafe output | rare | Moderate |
Document overrides; audit changes.
Measuring the model
Track per action:
| Metric | Signal |
|---|---|
| Block rate | User friction; sudden drops may mean bypass |
| Review rate | Staffing needs |
| Review override rate (approved as safe) | False positive indicator |
| Blocked-then-reported incidents | False negative indicator |
Tune policy when override rate spikes — not by disabling guardrails.
Implementation sketch
type Action = "allow" | "review" | "block";
function routeVerdict(verdict: string, categories: string[]): Action {
if (categories.some((c) => BLOCKING_CATEGORIES.has(c)) || verdict === "unsafe") {
return "block";
}
if (verdict === "suspicious") return "review";
return "allow";
}
Prefer category-aware rules over verdict-only switches. Align BLOCKING_CATEGORIES with your threat model.
Summary
- Allow — automated proceed; downstream controls still required
- Review — human or secondary adjudication; users never see raw flagged content
- Block — hard stop for high-confidence harm
- Map IdenticAPI
safe/suspicious/unsafe(orallow/review/block) through category-aware policy - Aggregate with block > review > allow precedence
- Measure override and incident rates to tune — not binary threshold guessing
The ternary model is how production teams ship guardrails users tolerate without giving attackers a wide allow path.
Frequently asked questions
What is the allow, review, block security model?
It is a ternary policy mapping detector verdicts to three application actions: allow (proceed), review (human or secondary adjudication), and block (hard stop). It reduces both false-positive user friction and false-negative exposure compared to binary allow/deny.
How do IdenticAPI verdicts map to allow, review, and block?
Common mapping: safe or allow → allow; suspicious or review → review queue; unsafe or block → block with static fallback. Secrets and executable markup should almost always block regardless of surface.
Should end users see content pending review?
No. Show a neutral holding message while reviewers adjudicate. Never display flagged model text with a warning banner — that still exposes harmful or executable content.
What is the precedence when multiple checks disagree?
Use block > review > allow — matching Unified Guard decision priority. One blocked check forces block even if other checks returned allow.
When should I block instead of review?
Block on unsafe verdicts, high risk, detected secrets, instruction overrides on public surfaces, unsafe HTML, and destructive agent actions. Reserve review for suspicious verdicts and context-dependent policy topics where false positives are likely.
Related reading
- Allow, Review or Block: Designing AI Agent Policies
Design practical AI agent policies with allow, review, and block decisions. Deterministic rules, policy evaluation order…
- When Should an AI Response Be Blocked vs Sent for Review?
Define when to block AI output outright vs route it for human review — verdict semantics, risk levels, and workflow desi…
- Fail-Open vs Fail-Closed AI Guardrails
Fail-open vs fail-closed guardrail behavior — trade-offs for chat, financial actions, customer-facing output, and destru…