Security and trust posture
Running agents in production raises three questions Catalyst is built to answer:
- Who is this agent? Can a downstream service prove that a request really came from a specific agent, and not from impersonated or hijacked credentials?
- What may this agent do? Are there enforceable limits on which MCP servers the agent can call and which data it can read or modify — limits that the LLM cannot reason its way around?
- What has this agent done? When something goes wrong, can the platform produce a record of what happened, by which identity, in what order?
Catalyst answers each of these at the infrastructure layer, so the answers stay consistent regardless of which agent framework, language, or LLM you use, and without requiring changes to MCP client or server code.
How Catalyst answers the three questions
| Question | Catalyst control |
|---|---|
| Who is this agent? | Every Catalyst workload — agent App IDs and any MCP server you run as a Catalyst app — receives a SPIFFE-based cryptographic identity that Catalyst issues, attests, and rotates automatically. All service-to-service traffic is mTLS-secured using these identities. No static API keys, no shared service tokens. |
| What may this agent do? | A Configuration resource with accessControl rules attached to each App ID decides which callers may reach it. Defaults can be set to deny, so an MCP server is unreachable until a calling App ID is explicitly allow-listed. A Dapr bearer middleware layered on the MCP server's HTTP pipeline adds JWT validation on top — the LLM cannot reason its way around either control. |
| What has this agent done? | Every service-invocation call — MCP calls included — flows through Catalyst's data plane and is captured in logs, metrics, and distributed traces. The Catalyst observability console shows which App ID called which target, when, and whether policy allowed or denied the call. |
Default postures
Catalyst's defaults favor refusal over permissiveness. None of the below requires you to "turn on a security mode" — they are how the platform behaves out of the box.
- No identity is implicit. An MCP server reached through Catalyst is mTLS-authenticated using the caller's SPIFFE identity. There is no anonymous service-invocation path.
- Access policies are declarative and explicit. An
accessControlblock attached to an MCP server's App ID withdefaultAction: denymakes the server unreachable until callers are explicitly allow-listed. - Secrets are never exposed to agent code. Plaintext credentials you attach to a bearer middleware component (issuer URLs, audiences, signing keys) are stored as managed secrets in your project's secret store. The agent receives tool results, not credentials.
- mTLS is on everywhere. You don't configure it; it isn't a per-resource flag.
Threat model
The failure modes below account for most of the security risk when agents operate in production. Catalyst's controls map directly to each.
| Failure mode | What it looks like | Catalyst control |
|---|---|---|
| Privilege escalation | A sub-agent inherits unscoped credentials and acts beyond its principal's authority. | Each agent's App ID has its own SPIFFE identity and its own accessControl configuration. Authority does not propagate by inheritance; every hop is independently authorized. |
| Unauthorized tool use | An agent or unknown caller tries to reach an MCP server it isn't entitled to use. | Configuration accessControl rules attached to the MCP server's App ID enforce per-caller allow/deny at the service-invocation boundary. Denied calls are rejected by Catalyst's data plane before they reach the MCP server process. |
| Jailbreaking | A prompt persuades the LLM to attempt an unauthorized action. | The LLM's decision happens before the platform; Catalyst's authorization checks run after. A jailbroken LLM that tries to reach a forbidden MCP server still hits a deny from accessControl (or a 401 from bearer middleware) before any code on the MCP server runs. |
| "Agent who?" | A downstream service cannot confirm which agent originated a call. | SPIFFE workload identity is verified at every hop. The MCP server (if it runs in Catalyst) or any downstream service the MCP server calls can read the caller's identity from the mTLS connection or from claims in the validated JWT. |
| Secret sprawl | API keys appear in logs, prompts, or downstream agent calls. | Credentials used by bearer middleware are resolved from the secret store at request time and never visible to agent code. SPIFFE SVIDs are short-lived and rotated by Catalyst automatically. |
| No provenance | No verifiable record of who did what. | Every service-invocation call is recorded by Catalyst's observability pipeline — logs, metrics, traces — and viewable in the console alongside policy decisions. |
What stays your responsibility
Catalyst draws the trust boundary at the platform's surface. Some risks live outside it.
- Prompt injection and LLM-layer attacks. Catalyst enforces authorization at the service-invocation boundary regardless of what the LLM does, but it does not inspect prompt content. Defense against prompt injection — content filters, allow-listing, output validation — belongs in your agent's pre-LLM and post-LLM layers.
- The security of the MCP server itself. When you connect to a third-party MCP server (GitHub, Stripe, Linear), Catalyst secures the connection, not the server. Vet third-party MCP servers as you would any other dependency.
- Audit sink durability and integrity. Catalyst emits observability data to your sinks; the long-term durability and tamper resistance of those records is governed by the sink you write to (your SIEM, log warehouse, immutable bucket). Choose a sink whose retention and integrity guarantees match your compliance obligations.
- Tool-level granularity. Today's
accessControlis keyed by caller App ID and target App ID. If a single MCP server exposes both low-risk and high-risk tools and you need to grant access to some but not others, split the tools across separate MCP servers (one App ID per server) so the policy boundary matches the trust boundary.
Identity model in one paragraph
Every Catalyst workload — agent App IDs and the MCP server itself if it runs as a Catalyst app — receives a SPIFFE-based cryptographic identity that Catalyst issues and rotates automatically. mTLS between workloads uses these identities. When an agent invokes an MCP server through Catalyst, the caller's SPIFFE identity is bound to the request; the MCP server's Configuration accessControl rules decide whether to allow it.
Next steps
- MCP access policies tutorial — declarative authorization per App ID with
ConfigurationaccessControl. - MCP authentication tutorial — end-to-end bearer middleware + OAuth 2.0 setup.
- MCP access control how-to — reference for
accessControlpolicy structure and patterns. - MCP OAuth2 how-to — reference for client-side and server-side OAuth 2.0 middleware configuration.