Skip to content

Security

Arbitus provides defense-in-depth security for MCP tool calls. This page covers the security-specific features that make Arbitus unique.

Standard regex-based filtering can be bypassed by encoding sensitive data as Base64, URL-encoding, double-encoding, or Unicode variants. Arbitus decodes all of these before applying block_patterns:

  • Base64 (standard and URL-safe)
  • Percent-encoding (single and double)
  • Unicode normalization (NFC)
  • Bidi-control character stripping

This means a payload like cGFzc3dvcmQ= (Base64 for “password”) will be caught by a block_patterns: ["password"] rule.

rules:
block_patterns: ["password", "api_key", "secret"]
filter_mode: block # default — reject the request entirely
rules:
block_patterns: ["password", "api_key", "secret"]
filter_mode: redact # scrub to [REDACTED] and forward

In redact mode, matching values in tool arguments are replaced with [REDACTED] and the sanitized request is forwarded. Upstream responses are always scrubbed regardless of filter_mode.

Enable built-in detection of prompt injection attempts:

rules:
block_prompt_injection: true

Seven built-in patterns detect common injection techniques like “ignore previous instructions”, “you are now”, and similar adversarial prompts. Matched requests are always blocked, even when filter_mode: redact is set.

For complex authorization logic, Arbitus integrates with the Open Policy Agent via Rego policy files:

rules:
opa:
policy_path: policy.rego
entrypoint: data.mcp.allow # must resolve to boolean

The policy input object contains:

FieldDescription
agent_idAgent name from MCP initialize
methodMCP method (e.g., tools/call)
tool_nameTool being called
argumentsTool call arguments
client_ipClient IP address

Example policy:

package mcp
import future.keywords.if
default allow := false
allow if {
input.tool_name == "read_file"
}
allow if {
input.agent_id == "ops-agent"
}

Policy file changes are picked up automatically via config hot-reload.

Validate tool call arguments against the inputSchema from tools/list:

rules:
validate_schema: true

Requests with invalid or unexpected fields are blocked before reaching the upstream.

When using stdio transport, verify MCP server binaries before spawning:

transport:
type: stdio
server: ["/usr/local/bin/mcp-server", "--data-dir", "/data"]
verify:
sha256: "e3b0c44298fc1c149afbf4c8996fb924..."
cosign_bundle: "/etc/mcp/server.bundle"
cosign_identity: "ci@example.com"
cosign_issuer: "https://token.actions.githubusercontent.com"

Both sha256 and cosign_bundle are optional and independent. If either check fails, the gateway aborts before spawning the process.

Arbitus supports multiple authentication methods with a clear priority chain:

  1. JWT Bearer — validate tokens against HMAC secrets, JWKS endpoints, or OIDC providers
  2. mTLS — mutual TLS with client certificate CN matching
  3. API Key — per-agent pre-shared keys via X-Api-Key header
  4. clientInfo.name — fallback to the MCP initialize message (no auth)

See Configuration — auth and Deployment — mTLS for setup details.

Sensitive tool calls can be suspended until a human operator approves them via REST API. This provides a manual safety net for high-risk operations.

See Usage — HITL for the full API reference.

Intercept and log tool calls without forwarding them to the upstream. Useful for safely observing what a new agent would do before granting real access.

See Usage — Shadow mode for configuration details.