One request from an AI agent, and every gate it passes through. Read left to right: the agent is untrusted, the model and tools sit behind the gates, and nothing reaches them except through Shield. Each gate names the audit signal it produces, so an alert can be traced back to the control that fired it.
Verified against the deployed data plane, 2026-07-28.
X-User-Role unless role binding is on. The audit records role_source so you can see which.guardrail=adversarial_detection or custom_policy_inputguardrail=rbac_guard · tool_allowlist · tool_call_validationguardrail=custom_policy_outputrole_source · agent_source · token_binding · acting_for| Priority | Signal | What it means | First action |
|---|---|---|---|
| P1 | role_source=header on a privileged role |
A caller named its own role. With binding off this is normal and unverifiable — which is the point. | Confirm binding mode. If prefer, this caller is sending no verified token. |
| P1 | token_binding=failed |
A bound credential arrived without a valid proof. This is the stolen-token signature. | Revoke the token by jti, then find where it leaked — logs, traces, a tool response. |
| P1 | Same agent_key, sudden new tool |
An agent doing something it has never done. Often prompt injection rather than compromise. | Killswitch the tool for that tenant; read the prompts in that session_id. |
| P2 | guardrail=custom_policy_input spike |
Repeated attempts against one of your own policies. Probing, or a broken integration. | Group by agent_key. One agent means a bug; many means an attack. |
| P2 | [monitor] would block on the MCP gateway |
The control plane would have denied this, but is in observe mode. | Count them for a week, then set SHIELD_MCP_CONTROL_PLANE=enforce. |
| P2 | Registry allows, enforcement denies | A data policy is vetoing a permission the console grants. The console is not the whole picture. | Reconcile the tool policy with the agent registry; the stricter layer wins. |
| P3 | delegation_verified=false with a header present |
An on-behalf-of token was presented and rejected. | Check issuer allowlist and audience — usually a misconfigured client, not an attack. |
| If this fails | Behaviour | Why |
|---|---|---|
| Shield unreachable from the app | Traffic is refused | The LangChain middleware is fail-closed by default. A timeout is not an approval. |
| Redis down | Replay and rate limits degrade; config falls back to defaults | "Cannot read config" must not mean "deny everything" — but replay protection is genuinely unavailable. |
| Model backend slow | Guarded calls take ~25s; the client may time out | Custom policies are model-evaluated. Budget for it in client timeouts. |
| An agent bypasses Shield | Every gate above is skipped | This is the assumption the whole design rests on. See below. |
Run examples/langchain/verify_deployment.py after each deploy: it
exercises gates 2 through 4 against the live data plane and reports the identity posture,
with a non-zero exit code so it can gate a release.