Back to Portfolio

AI Infrastructure Security

AgentTrust

Least-privilege identity and authorization for AI agent tool execution, implemented as an SDK-first guard for cooperative tool, MCP, and LangChain paths.

Stack

PythonJWTMCPLangChainLeast PrivilegeAuditAI Infrastructure

What This Demonstrates

AI security capabilities made inspectable.

AI Infrastructure Security

  • agent/run identity
  • guarded tool execution
  • LLM choice separated from authorization
  • explicit SDK trust boundary

Least Privilege

  • short-lived scoped credentials
  • per-agent policy grants
  • deny-by-default unknown agents
  • out-of-scope action rejection

MCP And Tool Access

  • MCP tool-to-scope mapping
  • guarded-client enforcement
  • denied calls blocked before client invocation
  • raw-client bypass called out explicitly

Auditability

  • allow and deny audit records
  • agent/run/tool/scope correlation
  • redacted argument capture
  • local JSONL audit sink

Problem And Constraints

Model-selected tools are not authorization.

LLM-driven applications may choose tools dynamically, but the host application must not treat a model-selected tool as an authorized action. AgentTrust explores the boundary between "the model requested this" and "the application authorizes this" with scoped per-run identity and guarded tool execution.

AgentTrust is an SDK-level authorization layer for cooperative first-party code.
Authorization applies only when calls are routed through guarded AgentTrust APIs.
Raw tool, shell, database, or MCP client access remains outside the SDK enforcement boundary.
Policies grant explicit scope patterns per known agent.
The current audit sink is local JSONL, not immutable or tamper-evident storage.
The MVP avoids a gateway, control plane, enterprise IAM, and production-scale authorization service.

System Architecture

SDK enforcement boundary for cooperative tool paths.

Component Responsibilities

Identity, policy, adapters, and audit stay separated.

AgentTrust SDK

Owns

  • run-scoped identity establishment
  • scope authorization
  • guarded direct and async calls

Exposes

  • start run
  • call
  • acall
  • guarded decorator

Depends on

  • policy configuration
  • JWT signing secret
  • local process time

Persistence

No application database; local audit sink is configured by path

Guarded Adapters

Owns

  • MCP tool-to-scope mapping
  • LangChain tool wrapping
  • delegation into AgentRun authorization

Exposes

  • GuardedMCPClient
  • as_langchain_tool
  • as_langchain_tools

Depends on

  • AgentRun
  • wrapped client or function
  • developer routing through wrapper

Persistence

Adapter decisions are recorded through the shared audit sink

Request Flow

Authorization precedes execution.

Guarded Tool Execution

The host starts a run for a known agent, AgentTrust establishes scoped run identity from policy, and each guarded tool call is authorized before the underlying tool or MCP client is invoked.

Where controls apply

  • Authorization precedes execution for guarded calls.
  • Unknown agents and out-of-scope actions fail closed.
  • Serialized JWT verification exists, while guarded calls use the established in-process identity.

Engineering Decisions

Security trade-offs with the boundary named.

SDK-first enforcement instead of gateway

Source ADR
Context
The first milestone needed to be easy to embed in existing agent applications without introducing a network service.
Decision
Keep enforcement in the application process and route cooperative tool calls through AgentTrust.
Trade-off
Integration stays lightweight, but code with raw-client access can bypass the SDK boundary.

Short-lived scoped run identity

Source ADR
Context
Long-lived agent-level authority makes it harder to correlate and bound individual tool sessions.
Decision
Issue per-run identity containing agent ID, run ID, scopes, token ID, issuer, issued-at time, and expiry.
Trade-off
Capability exposure and audit correlation improve, while revocation and key rotation remain future hardening.

Guarded adapters

Source ADR
Context
LLM-selected tools should not execute merely because the model chose them.
Decision
Route direct calls, LangChain tools, and MCP client calls through the same AgentRun authorization path.
Trade-off
Authorization-before-execution is consistent for guarded paths, but security depends on calls staying inside the wrapper.

Local JSONL audit

Source ADR
Context
The SDK needed an inspectable audit trail without requiring infrastructure.
Decision
Write local JSONL audit events for guarded allow, deny, and error outcomes.
Trade-off
The trail is transparent and portable, but it is not immutable or tamper-evident.

Authorization Failure Behavior

Fail-closed behavior inside guarded paths.

Implemented behavior

Unknown agent

A run cannot be started when no policy exists for the agent.

Implemented behavior

Out-of-scope action

The guarded call writes a deny audit event and raises ToolDenied before execution.

Implemented behavior

Expired run identity

AgentRun checks expiry before guarded execution and denies expired identities.

Implemented behavior

Tampered or wrong-secret token

The JWT verification helper fails closed for covered invalid token cases.

Implemented behavior

Missing MCP scope mapping

The guarded MCP wrapper can fail closed when default-to-tool-name fallback is disabled.

Implemented behavior

Tool execution error

Allowed guarded calls audit an error status when the underlying callable raises.

Security Boundaries

The boundary is explicit, not implied.

Host / Agent

then

AgentTrust guarded execution boundary

then

Guarded adapter

then

Tool / MCP client
Raw MCP client / raw tool reference
Code retaining a raw MCP session, raw client, or direct tool reference can bypass SDK-level enforcement.
The enforced path is AgentRun.call, AgentRun.acall, AgentRun.guarded, GuardedMCPClient, and supported guarded adapters.
A caller with direct raw-tool or raw-client access can bypass SDK-level enforcement.
Policies map known agent IDs to allowed scope patterns.
MCP tools resolve to required scopes through explicit mappings, metadata, custom resolvers, or optional tool-name fallback.
JWT verification exists, but guarded tool calls use the established in-process run identity.
Local JSONL audit logging is not tamper-evident or immutable.

Auditability

Audit records provide local accountability.

Audit events correlate agent ID, run ID, token ID, tool, required scope, decision, reason, redacted arguments, result status, and timestamp.
The CLI can display local audit records with filters for agent and decision.
Redaction is key-name based and truncates long strings.
Audit logging is local SDK evidence, not centralized SIEM or non-repudiation evidence.

Threat Model

Mitigations stay inside the stated boundary.

The threat model is intentionally scoped to SDK-level cooperative enforcement. It is strongest against unauthorized tool selection inside guarded paths and intentionally does not claim protection from raw-client bypass or compromised hosts.

Prompt-injected agent selects unauthorized tool

MITIGATED

Guarded calls authorize the required scope before execution.

Only applies when the host routes the call through AgentTrust.

Unknown or out-of-scope action

MITIGATED

Unknown agents and missing scopes fail closed in the guarded path.

Policy authors can still grant overly broad scopes.

Expired, tampered, or wrong-secret credential

MITIGATED

Automated tests verify fail-closed expiry and JWT validation behavior.

No revocation or key rotation exists in the current MVP.

Overly broad policy

PARTIALLY MITIGATED

Scope grants are explicit and inspectable.

AgentTrust cannot infer business intent or prevent unsafe wildcard grants.

Raw client or tool bypass

NOT MITIGATED

The docs and architecture mark this as outside the SDK boundary.

Code with direct references can call tools without AgentTrust.

Compromised host process

NOT MITIGATED

None within the SDK-first boundary.

A compromised process can bypass wrappers, read secrets, or alter audit files.

Audit file modification

NOT MITIGATED

Events are appended under a process lock for cooperative execution.

Filesystem access can modify, truncate, or delete local JSONL audit records.

Verified Runtime Evidence

Verified Runtime Evidence

The primary evidence scenario is a public-safe MCP-style demo proving authorization-before-execution for guarded calls. Credential validation is documented as automated-test evidence, not runtime-demo evidence.

Runtime demo evidence

Authorization before MCP-style execution

An ops-reader run is granted only service.read. The allowed read invokes the fake MCP client once; the denied service.restart call raises ToolDenied and leaves the underlying invocation count at zero.

Agent: ops-reader
ALLOW service.read underlying_invoked=True invocation_count=1
DENY service.restart tool_denied=True underlying_invoked=False invocation_count=0
AUDIT ALLOW service.read
AUDIT DENY service.restart
Result
The denied MCP-style action is audited and blocked before the fake underlying client executes.
Boundary
This is guarded-client SDK evidence; it does not prove gateway enforcement or raw-client containment.

Automated test evidence

Credential validation

Tests cover expired run identities, expired serialized JWTs, tampered tokens, wrong signing secrets, and malformed scope claims.

PYTHONDONTWRITEBYTECODE=1 python3 -m pytest -p no:cacheprovider
48 passed, 3 skipped
Skipped: real MCP SDK integration tests when mcp is not installed
Result
Covered invalid credential cases fail closed through TokenError or ToolDenied paths.
Boundary
This does not claim token revocation, signing-key rotation, or a remote token-introspection service.

Runtime demo evidence

Allow and deny audit trail

The same demo emits one ALLOW and one DENY audit line with the same synthetic agent/run context, tool, required scope, decision, and execution status.

ALLOW agent=ops-reader run=<synthetic> tool=service.read scope=service.read status=ok
DENY  agent=ops-reader run=<synthetic> tool=service.restart scope=service.restart status=not_executed
Result
Guarded calls produce local audit records for allowed and denied tool attempts.
Boundary
Local JSONL audit is not immutable, tamper-evident, centralized, or SIEM-integrated.

Verified locally with synthetic data for calls routed through AgentTrust guarded execution APIs. This does not demonstrate process isolation or protection against raw-client bypass.

View Full Runtime Evidence →

Verified Behavior

Verified behavior without hard-isolation claims.

Runtime demo: scoped call allowed

The MCP-style evidence demo allows service.read for ops-reader and invokes the fake client once.

Runtime demo: out-of-scope call denied

The same run denies service.restart with ToolDenied because only service.read is granted.

Runtime demo: denied call does not execute

The denied MCP-style call leaves the fake underlying service.restart invocation count at zero.

Runtime demo: allow and deny audited

The demo prints ALLOW service.read and DENY service.restart audit records for the same run.

Automated tests: invalid credentials rejected

Expired, tampered, wrong-secret, and malformed-scope credential cases fail closed in tests.

Automated tests: unknown agent denied

Starting a run for an agent missing from policy raises PolicyError.

Automated tests: adapter coverage

Direct, async, decorator, MCP wrapper, and LangChain guarded paths are covered by local tests.

Verified environment caveat

The latest local run reported 48 passed and 3 skipped; skipped tests were real MCP SDK integration tests because the dependency was not installed.

Trade-offs And Limitations

Limitations that sharpen the security story.

Trade-offs

SDK-first enforcement keeps integration lightweight but cannot stop code that bypasses the SDK.
HS256 signing keeps the MVP small, while asymmetric signing and key rotation remain future hardening.
Tool-name fallback can simplify MCP mapping, but explicit mapping is stronger for fail-closed demos.
Local JSONL audit is transparent and portable, but not tamper-evident.
Redaction avoids obvious key-name leaks, but does not perform comprehensive PII detection.

Non-goals

No process isolation or sandboxing.
No protection from a compromised host process.
No containment for malicious tool implementations after an allowed call.
No centralized policy/control plane, enterprise IAM, or multi-tenant authorization service.
No token revocation, signing-key rotation, SIEM integration, or immutable audit storage.
No production-scale authorization, performance, adoption, or live MCP deployment claims.

Future Extensions

Future hardening, not current promises.

Out-of-process enforcement gateway for hard mediation.
Asymmetric credentials and signing-key rotation.
Durable or tamper-evident audit backend.
Explicit token revocation.
Centralized policy and control plane.