Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 64 additions & 19 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,75 @@
}
],
"words": [
"GitHub",
"Markdown",
"README",
"TypeScript",
"JavaScript",
"Python",
"PyPI",
"NuGet",
"OpenSSF",
"A2A",
"appsettings",
"asyncio",
"backdoors",
"Behaviour",
"behavioural",
"Blocklist",
"bursty",
"bytecodes",
"CD",
"cedarpy",
"CI",
"CLI",
"cmdshell",
"CODEOWNERS",
"CodeQL",
"CORS",
"CSP",
"CLI",
"CI",
"CD",
"PR",
"MCP",
"A2A",
"dataclass",
"deque",
"DSPM",
"Entra",
"EUAI",
"FIPS",
"GitHub",
"gomod",
"GPAI",
"gvisor",
"HMAC",
"IMDS",
"JavaScript",
"Kata",
"lockfiles",
"Markdown",
"maxlen",
"MCP",
"MediatR",
"Merkle",
"backdoors",
"metacharacters",
"metacharacter",
"Blocklist"
"metacharacters",
"myregistry",
"Newtonsoft",
"NuGet",
"OpenSSF",
"pids",
"Portkey",
"PR",
"pydantic",
"PyPI",
"Pytest",
"Python",
"quickstarts",
"README",
"rego",
"runsc",
"sandboxing",
"SARIF",
"scikit",
"seccomp",
"Serilog",
"setuptools",
"SIEM",
"SPIFFE",
"SVID",
"syscall",
"thiserror",
"TOCTOU",
"TypeScript",
"VADP"
],
"ignorePaths": [
"**/node_modules/**",
Expand All @@ -47,4 +92,4 @@
"**/*.json",
"**/*.lock"
]
}
}
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- **.NET MCP Protocol Support** — Full Model Context Protocol governance layer multi-targeting .NET 8.0 and .NET 10.0 with 11/12 OWASP MCP Security Cheat Sheet coverage
- `McpGateway`: 5-stage pipeline (deny-list → allow-list → sanitization → rate-limiting → human approval)
- `McpSecurityScanner`: 6-threat detection (tool poisoning, rug-pull, cross-server, description injection, schema abuse, protocol attacks)
- `McpSessionAuthenticator`: Cryptographic session binding with TTL and TOCTOU-safe concurrency
- `McpMessageSigner`: HMAC-SHA256 message integrity + ML-DSA-65 post-quantum signing on .NET 10+ (NIST FIPS 204)
- `McpResponseScanner`: Output validation (HTML tags, imperatives, credential leakage, data exfiltration)
- `CredentialRedactor`: 10 credential pattern redaction (API keys, tokens, PEM, connection strings)
- `McpSlidingRateLimiter`: Per-agent sliding window rate limiting
- ASP.NET Core integration: `AddMcpGovernance()`, `UseMcpGovernance()`, `MapMcpGovernance()`
- `IConfiguration` binding, `ILogger<T>` structured logging, `IHealthCheck` implementation
- gRPC server interceptor (all 4 handler types)
- `[McpTool]` attribute for auto-discovery with `McpToolRegistry`
- OpenTelemetry: 4 MCP-specific counters (decision, threat, rate-limit, scan)
- `AgentGovernance.ModelContextProtocol` adapter sub-package for official MCP SDK integration
- 2 sample apps: ASP.NET Core full-stack and Official MCP SDK integration
- K8s MCP server hardening guide (`docs/deployment/mcp-server-hardening.md`)

### Security
- **Hardened CLI Error Handling** — standardized sanitized JSON error output across all 7 ecosystem tools to prevent internal information disclosure (CWE-209).
- **Audit Log Whitelisting** — implemented strict key-whitelisting in `agentmesh audit` JSON output to prevent accidental leakage of sensitive agent internal state.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ Still have questions? File a [GitHub issue](https://github.com/microsoft/agent-g
- [Agent SRE](packages/agent-sre/) | [Observability integrations](packages/agent-hypervisor/src/hypervisor/observability/)
- **MCP Security Scanner**: Detect tool poisoning, typosquatting, hidden instructions, and rug-pull attacks in MCP tool definitions
- [MCP Scanner](packages/agent-os/src/agentos/mcp_security.py) | [CLI](packages/agent-os/src/agentos/cli/mcp_scan.py)
- **.NET MCP Protocol Support**: Full governance pipeline for .NET 8.0 — 5-stage gateway, 6-threat scanner, session auth, message signing, credential redaction (11/12 OWASP MCP sections)
- [.NET MCP SDK](packages/agent-governance-dotnet/) | [Official MCP SDK Adapter](packages/agent-governance-dotnet/src/AgentGovernance.ModelContextProtocol/)
- **Trust Report CLI**: `agentmesh trust report` — visualize trust scores, task success/failure, and agent activity
- [Trust CLI](packages/agent-mesh/src/agentmesh/cli/trust_cli.py)
- **Secret Scanning & Fuzzing**: Gitleaks workflow, 7 fuzz targets covering policy, injection, sandbox, trust, and MCP
Expand Down
191 changes: 191 additions & 0 deletions docs/deployment/mcp-server-hardening.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# MCP Server Hardening Guide

Deployment guidance for running MCP tool servers securely, aligned with
[OWASP MCP Security Cheat Sheet §3 — Sandbox & Isolate MCP Servers](https://cheatsheetseries.owasp.org/cheatsheets/MCP_Security_Cheat_Sheet.html).

## Transport: prefer stdio over HTTP

When the MCP server runs on the same host as the agent, use **stdio** transport
rather than HTTP/SSE. This eliminates the network attack surface entirely —
no open ports, no TLS configuration, no SSRF vectors.

```yaml
# docker-compose.yml — stdio transport
services:
mcp-server:
image: myregistry/mcp-tools:1.2.3@sha256:abc...
stdin_open: true
read_only: true
security_opt: ["no-new-privileges"]
```

For HTTP transport, require mTLS between agent and server (see §6).

## Kubernetes: securityContext

Every MCP server pod should run as a non-root user with a read-only root
filesystem and all capabilities dropped:

```yaml
apiVersion: v1
kind: Pod
metadata:
name: mcp-server
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
runAsGroup: 65534
fsGroup: 65534
seccompProfile:
type: RuntimeDefault
containers:
- name: mcp-tools
image: myregistry/mcp-tools:1.2.3@sha256:abc...
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
limits:
cpu: "500m"
memory: "256Mi"
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir:
sizeLimit: 50Mi
```

## Network Isolation: NetworkPolicy

Restrict MCP servers so they can **only** communicate with the agent
orchestrator and required backends (database, blob storage). Block all
egress to the public internet and to the cloud metadata service:

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mcp-server-policy
spec:
podSelector:
matchLabels:
app: mcp-server
policyTypes: [Ingress, Egress]
ingress:
- from:
- podSelector:
matchLabels:
app: agent-orchestrator
ports:
- port: 8080
protocol: TCP
egress:
# Allow DNS
- to:
- namespaceSelector: {}
ports:
- port: 53
protocol: UDP
# Allow specific backends
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- port: 5432
protocol: TCP
# Block cloud metadata (SSRF protection)
# Azure IMDS: 169.254.169.254
# AWS IMDS: 169.254.169.254
# GCP metadata: metadata.google.internal (100.100.100.200)
# These are blocked by default when no egress rule matches.
```

## gVisor / Kata Containers for Untrusted Servers

For MCP servers that execute arbitrary code (code interpreters, shell tools),
use a sandbox runtime like [gVisor](https://gvisor.dev/) or
[Kata Containers](https://katacontainers.io/):

```yaml
# AKS with gVisor runtime class
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
name: mcp-code-interpreter
spec:
runtimeClassName: gvisor
containers:
- name: interpreter
image: myregistry/code-interpreter:1.0@sha256:def...
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
```

On **Azure Kubernetes Service (AKS)**:
- Enable the [AKS Kata Containers documentation](https://learn.microsoft.com/azure/aks/) for VM-level isolation guidance.
- Use [Azure Container Instances (ACI)](https://learn.microsoft.com/azure/container-instances/) with Hyper-V isolation for per-tool ephemeral sandboxes.

## File System Restrictions

MCP tools should only access explicitly mounted paths:

```yaml
volumeMounts:
- name: workspace
mountPath: /workspace
readOnly: false # only if tool needs write
- name: config
mountPath: /config
readOnly: true
```

Combine with the `.NET SDK path traversal sanitization pattern`
(`SanitizationDefaults.AllPatterns` detects `../` sequences) to prevent
escape even if mounts are misconfigured.

## Resource Limits

Prevent a compromised tool from consuming cluster resources:

| Resource | Recommendation |
|----------|---------------|
| CPU | 500m limit per tool pod |
| Memory | 256Mi limit (512Mi for code interpreters) |
| Ephemeral storage | 50Mi via emptyDir sizeLimit |
| Process count | `pids-limit` cgroup (64 for simple tools) |
| Network bandwidth | Use Cilium/Calico bandwidth annotations |

## Checklist

- [ ] Non-root user (`runAsNonRoot: true`)
- [ ] Read-only root filesystem
- [ ] All capabilities dropped
- [ ] seccomp profile enabled (`RuntimeDefault`)
- [ ] NetworkPolicy restricts ingress + egress
- [ ] Cloud metadata IPs blocked (169.254.169.254)
- [ ] Resource limits set (CPU, memory, storage)
- [ ] gVisor/Kata for code execution tools
- [ ] stdio transport where possible
- [ ] Container images use SHA digest tags
- [ ] `.NET SDK McpGateway` sanitization + response scanning enabled

## Related

- [McpGateway](../../packages/agent-governance-dotnet/README.md#mcp-protocol-support) — 5-stage governance pipeline
- [McpSecurityScanner](../../packages/agent-governance-dotnet/README.md#mcp-protocol-support) — tool definition scanning
- [OWASP MCP Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/MCP_Security_Cheat_Sheet.html)
Loading
Loading