Chapter 10 · Reference

Security Cheatsheet

The one-page lookup. The order security checks run in, the configuration knob behind each layer, a checklist to run before you ship, a glossary, and where to read deeper. Bookmark this page.

The seven layers at a glance

Each layer answers one question and is implemented by different code. This is the map; click through for the detail.

# Layer Answers Lives in
1 Identity & Access Who is calling? Infrastructure.AI.MCPServer, Infrastructure.AI/A2A, Presentation.AgentHub
2 Autonomy & Governance How much may it do alone? Domain.AI/Governance, Application.AI.Common/MediatRBehaviors
3 Tools & Permissions Which tools, right now? Infrastructure.AI/Permissions, Application.Core/Permissions
4 Sandbox & Execution What can its code touch? Infrastructure.AI/Sandbox, Infrastructure.AI/Attestation
5 Egress & SSRF Where on the network? Infrastructure.AI/Egress, Infrastructure.AI.MCP/Services
6 Content Safety Is the text safe, in and out? Application.AI.Common/MediatRBehaviors, Infrastructure.AI.Governance
7 Data Protection What can it see and keep? Infrastructure.AI.KnowledgeGraph/Scoping, .../Compliance

The security pipeline order

Most runtime security runs as MediatR pipeline behaviors — interceptors that wrap every command. The agent behaviors are registered in src/Content/Application/Application.AI.Common/DependencyInjection.cs and are deliberately registered first so they form the outermost wrapper. A request descends through them on the way in; the response climbs back out through them in reverse.

MediatR pipeline behavior

A wrapper that runs around a command handler — like middleware, but for in-process commands. Each behavior can inspect the request, short-circuit it (return early without calling the handler), or modify the response on the way out. Registration order is execution order, outer to inner.

The security-relevant behaviors, in the order they execute (outer → inner):

  1. Inbound · screening
    AuditTrailContentSafetyPromptInjection
  2. Center
    The command handler runs (the LLM turn / tool call)
  3. Outbound · sanitizing
    ResponseSanitization acts on the result as it unwinds back out

So input is screened (content safety, injection scan) before the handler ever calls the model, and tool output is sanitized after the handler, before it can re-enter the model's context. Two more Application-level behaviors — RequestValidation (FluentValidation at the boundary) and Authorization — run on the inner ring for every command.

Tool permission and governance are not MediatR behaviors. They run on the live tool-execution path: every agent tool is wrapped by GovernedAIFunction, whose InvokeCoreAsync runs three ambient gates — IToolInvocationGovernor (authorization), IToolClassificationGate (data-classification DLP), and IProgressEvaluator (spin guard) — before the tool runs. Two earlier behaviors named ToolPermissionBehavior and GovernancePolicyBehavior were removed as dead code (they keyed on a marker nothing implemented).

!
Order is load-bearing

If you add a new security behavior, where you register it decides what it can see. A check that must run before the LLM call belongs among the inbound screening behaviors; a check on model output belongs at or after ResponseSanitization. Registering it in the wrong place can silently make it a no-op.

Configuration knobs, by layer

The harness ships closed-by-default; opening it up is a set of deliberate config choices. These are the security-relevant settings and where they live. For the full configuration reference, see the Developer Guide's Configuration page.

Layer Knob What it controls
Identity MCP.Server.Authentication (Authority / Audience / ValidIssuers) JWT validation for inbound MCP clients. Production requires it.
Identity AgentHub:Cors:AllowedOrigins The CORS origin allowlist. Never wildcard in production.
Identity Auth:Disabled (Development only) Disables auth — only honored when IsDevelopment() is also true.
Autonomy Autonomy tier (TierPolicies / agent SubagentType) Restricted / Supervised / Autonomous default posture per agent.
Tools Plugin AllowedTools / DeniedTools / AutonomyLevel Per-plugin tool boundary. DeniedTools is bypass-immune.
Sandbox SandboxConfigResourceLimits Memory / CPU-time / subprocess / disk caps; isolation mode.
Sandbox AttestationKeyOptions:HmacKeys (User Secrets / Key Vault) HMAC signing keys for tool-result attestation. Never in appsettings.
Egress Skill manifest egress.allowlist Additive per-skill hostname allowlist over the frozen default-deny baseline.
Content safety GovernanceConfig: Enabled, EnablePromptInjectionDetection, EnableResponseSanitization, InjectionBlockThreshold, ResponseBlockThreshold Toggles and thresholds for injection scanning and response sanitization.
Data AI:Governance:DataClassification:Mode (Off / Audit / Enforce) Purview data-classification DLP gate on the tool path. Off = inert; Audit = log verdicts; Enforce = block or redact by sensitivity label. Requires a classification provider enabled.
Data MultiTenantIsolation Enables per-tenant / per-owner record filtering. Off = single-tenant mode.
Data GraphRag.ProvenanceEnabled Stamps source pipeline / task / timestamp on every graph write.
Secrets AzureKeyVaultUri Loads secrets from Key Vault via managed identity (non-DEBUG builds).
!
Verify key names against your build

Config keys are listed here by their conceptual path. Casing and nesting can drift between versions — confirm the exact key in your appsettings.json and the AppConfig hierarchy before relying on it. The layer pages link the class that reads each one.

Pre-merge security checklist

Before a change that touches agent behavior, tools, or data goes in, walk this list. The first item is enforced mechanically; the rest are judgment.

  • OWASP Agentic evals pass. Run dotnet test --filter "Category=OwaspAgentic". A failure blocks the merge by default. See OWASP Agentic Evals.
  • No hardcoded secrets. Secrets come from User Secrets (dev) or Key Vault (prod) — never appsettings or source. Run dotnet list package --vulnerable when adding dependencies.
  • New tool? It declares its capabilities ([ToolCapabilityAttribute]) and registers with a keyed-DI string key. By default it can touch nothing. See Sandbox.
  • New outbound host? It is on an egress allowlist. The default is deny-all; an un-allowlisted host is blocked at runtime. See Egress & SSRF.
  • New command? It has a FluentValidation validator and the right [Authorize] / autonomy posture. Input is validated at the boundary, not inside the handler.
  • New security behavior? It is registered in the correct pipeline position (see the pipeline order above).
  • Destructive or high-risk action? It is gated behind an autonomy tier or an escalation strategy — never auto-approved. See Autonomy & Governance.

Glossary

Prompt injection
Hostile instructions hidden in content the agent reads, meant to override its real task. Direct = in the user's prompt; indirect = planted in a page, document, or tool result the agent will later consume.
SSRF (Server-Side Request Forgery)
Tricking your own server into making a network request on the attacker's behalf — typically to reach an internal address or the cloud metadata service the attacker can't reach directly.
DNS rebinding
An attack where a hostname passes a name-based check, then its DNS record is flipped to an internal IP before the actual connection — defeated by checking the IP at connect time, not at URL-parse time.
Capability model
A permission scheme where code can do nothing unless it was explicitly granted a named capability (file read, network, subprocess, …). The harness's sandbox is closed-by-default: no capability means no access.
HMAC attestation
A keyed cryptographic signature over a tool execution's input/output hashes and timestamp. Only a holder of the secret key can produce or verify it, so a result can't be forged or tampered with after the fact.
Bypass-immune
A Deny rule that an auto-approve or Autonomous-tier setting cannot override. A plugin's DeniedTools and the sandbox safety gates are bypass-immune.
Fail closed
When a control errors or is misconfigured, it denies rather than allows. A quorum approval with a broken threshold denies; an egress request with no identity is refused.
Memory poisoning
Planting a false "fact" in the agent's persistent memory in one session to mislead a later one. Countered by provenance stamping and per-tenant/owner isolation.
Confused deputy
Tricking a privileged component (the agent) into misusing its authority on behalf of a less-privileged caller. Countered by carrying the real caller identity through every authorization check.

Deep-dive references

Longer, code-level writeups that sit alongside this guide:

The one sentence to remember

Everything the model reads or writes is untrusted; every capability is closed until granted; every control fails closed; and no control stands alone. If a change you're making violates one of those four, it's probably a security regression.