Enforcement First Security¶
CapiscIO operates on a simple principle: Enforcement First. Before an agent processes a single byte of a request, it must verify the Identity of the calling agent and the Integrity of the message.
The Trust Model¶
Key Concept: Self-Issued Keys
CapiscIO does not issue agent identities. Each agent generates its own Ed25519 keypair. Guard verifies identities using keys you provision — similar to how SSH uses known_hosts.
How it works today:
- Each agent generates its own keys (Ed25519 keypair)
- Public keys are shared manually (copied to trust stores)
- Guard verifies signatures against keys in the local trust store
This is intentional. We enforce identity verification at the protocol layer without requiring a central authority. You control which agents you trust.
What's Coming
We're designing a Registry with early partners to enable dynamic key discovery and revocation. Today's file-based model will remain supported as a fallback.
The "Customs Officer" Model¶
Think of SimpleGuard as a Customs Officer at the border of your agent. It stops every request and asks three questions:
- "Who are you?" (Agent Identity)
- "Did you really say this?" (Payload Integrity)
- "Is this current?" (Freshness / Replay Protection)
If any answer is "No", the request is rejected immediately.
1. Agent Identity Verification (Trust Badge)¶
CapiscIO uses Trust Badges (signed JWS tokens per RFC-002) with Ed25519 keys to prove agent identity.
The Handshake¶
- Sender: Signs the request using their private key.
- Header: The request includes an
X-Capiscio-Badgeheader containing the signature (RFC-002 §9.1). - Receiver:
- Extracts the Key ID (
kid) from the header. - Looks up the public key in the local Trust Store (
./capiscio_keys/trusted/). - Verifies the signature.
- Extracts the Key ID (
Zero-Config Dev Mode¶
When initialized with dev_mode=True, SimpleGuard automatically:
- Generates a new Ed25519 keypair in
./capiscio_keys/. - Creates an
agent-card.jsonwith the public key. - Adds the public key to the local Trust Store (Self-Trust).
Adding External Agents to Your Trust Store¶
To accept requests from another agent:
# Copy their public key to your trust store
cp /path/to/other-agent/capiscio_keys/public.pem \
./capiscio_keys/trusted/{their-key-id}.pem
The {their-key-id} must match the kid claim in their JWS headers.
Manual Key Management
Today, you manage trust stores manually (like SSH known_hosts). For production deployments with many agents, we recommend automating this via your existing PKI, Vault, or deployment tooling.
2. Integrity Verification (Body Hash)¶
Identity is not enough. An attacker could intercept a valid signed request and change the body (e.g., "Transfer $10" → "Transfer $1M").
To prevent this, CapiscIO enforces Payload Integrity using a Body Hash (bh) claim.
The Process¶
- Sender:
- Calculates
SHA-256(HTTP Body). - Adds the hash to the JWS payload as claim
bh. - Signs the JWS.
- Calculates
- Receiver:
- Verifies the JWS signature (Identity).
- Calculates
SHA-256(Received HTTP Body). - Compares the calculated hash with the
bhclaim.
If the hashes do not match, SimpleGuard raises a VerificationError and returns 403 Forbidden.
3. Freshness / Replay Protection¶
Even with valid identity and integrity, an attacker could capture a legitimate request and replay it.
CapiscIO enforces Freshness using timestamp claims per RFC-002 §8.1:
iat(issued at): When the badge was issuedexp(expires): When the badge expires
Guard rejects requests outside a 60-second clock skew tolerance window. Both iat and exp are validated with this tolerance applied, allowing for clock drift in distributed systems.
Badge Verification Algorithm (RFC-002 §8.1)¶
When verifying a Trust Badge, the Guard performs these checks in order:
- Decode JWS — Parse the badge as a signed JSON Web Signature
- Validate signature — Verify using the issuer's public key
- Check
iat— Reject ifiatis in the future (minus clock tolerance) - Check
exp— Reject if current time is pastexp(plus clock tolerance) - Validate
iss— Confirm issuer is in trusted issuers list - Validate
sub— Confirm subject DID format is valid - Check
ial— Validate IAL claim is"0"or"1" - Validate
key— Confirm public key JWK is well-formed - If IAL-1, validate
cnf— Check confirmation key binding (RFC 7800) - Trust level policy — Check if
vc.credentialSubject.levelmeets minimum required level
Error Codes (RFC-002 §8.5)
When verification fails, the Guard returns specific error codes: BADGE_EXPIRED, BADGE_NOT_YET_VALID, INVALID_SIGNATURE, UNTRUSTED_ISSUER, INVALID_DID, TRUST_LEVEL_INSUFFICIENT. See RFC-002 §8.5 for the complete error code reference.
4. Performance Telemetry¶
Security shouldn't slow you down. CapiscIO adds negligible overhead (<1ms) and proves it with every response.
Check the Server-Timing header in any response:
dur: Duration in milliseconds.desc: Description of the operation.
5. Policy Enforcement (PDP Integration)¶
Badge verification answers "who is calling?" — but not "are they allowed to do this?". Policy enforcement adds authorization decisions via a Policy Decision Point (PDP).
How It Works¶
The Policy Enforcement Point (PEP) sits between badge verification and your route handlers. After a badge is verified, the PEP asks an external PDP whether the request should proceed.
┌─────────┐ ┌─────────────┐ ┌─────┐ ┌──────────────┐
│ Request │────▶│ Badge │────▶│ PEP │────▶│ Your Handler │
│(+ badge) │ │ Verification│ │ │ │ │
└─────────┘ └─────────────┘ └──┬──┘ └──────────────┘
│
┌────▼────┐
│ PDP │
│(external)│
└─────────┘
The PEP sends a PIP request (Policy Information Point) containing identity, action, and resource attributes. The PDP returns ALLOW or DENY, plus optional obligations the PEP must enforce.
Enforcement Modes¶
Four modes control how strictly the PEP enforces PDP decisions. They form a total order from most permissive to most restrictive:
| Mode | PDP Denies | PDP Unavailable | Unknown Obligation |
|---|---|---|---|
| EM-OBSERVE | Log only, allow through | Allow (emit ALLOW_OBSERVE) | Log, skip |
| EM-GUARD | Block request | Deny (fail-closed) | Log, skip |
| EM-DELEGATE | Block request | Deny (fail-closed) | Log warning, proceed |
| EM-STRICT | Block request | Deny (fail-closed) | Deny request |
Start with EM-OBSERVE to monitor decisions without affecting traffic, then tighten as your policies mature.
Obligations¶
A PDP can attach obligations to an ALLOW decision — actions the PEP must perform before forwarding the request. Examples from the RFC:
| Obligation Type | Purpose | Example Params |
|---|---|---|
rate_limit.apply | Enforce per-agent rate limits | { "rpm": 100, "key": "agent-did" } |
redact.fields | Remove sensitive fields | { "fields": ["/pii/email"] } |
log.enhanced | Enhanced audit logging | { "level": "audit" } |
require_step_up | Require human review | { "mode": "human_review" } |
How the PEP handles obligation failures depends on the enforcement mode. In EM-STRICT, failing to enforce any known obligation blocks the request. In EM-OBSERVE, failures are logged but the request proceeds.
Decision Caching¶
The PEP caches ALLOW decisions to reduce PDP latency. Cache keys are derived from the agent DID, badge JTI, operation, and resource. The effective TTL is the minimum of:
- The PDP-returned
ttl - The badge
exp(expiry) - The envelope
expires_at(if present)
DENY decisions are not cached by default.
Break-Glass Override¶
For emergencies, a break-glass token bypasses the PDP entirely. The token is a signed JWS (EdDSA) with a scoped grant and an expiry (recommended: 5 minutes). It skips authorization but not authentication — the badge must still be valid.
The PEP emits capiscio.policy.override = true telemetry for audit when a break-glass token is used.
Break-Glass Keys
Use a separate Ed25519 keypair for break-glass tokens. Do not reuse your CA badge-signing key.
Badge-Only Mode¶
If no PDP endpoint is configured, the PEP is a no-op passthrough. Badge verification still runs, but no policy decisions are made. This is the default behavior.
Getting Started
See Policy Enforcement Setup for step-by-step configuration.
Summary: What Guard Does and Doesn't Do¶
| Guard Does | Guard Doesn't |
|---|---|
| ✅ Verify agent identity (Ed25519 signatures) | ❌ Issue identities (you generate keys) |
| ✅ Enforce payload integrity (SHA-256 body hash) | ❌ Manage a central registry (coming soon) |
| ✅ Block replay attacks (timestamp validation) | ❌ Replace your IAM/SSO (human auth) |
| ✅ Work with keys you provision | ❌ Auto-discover external agent keys (coming soon) |
| ✅ Enforce PDP policy decisions (when configured) | ❌ Provide a PDP (bring your own) |
| ✅ Support break-glass emergency overrides | ❌ Bypass authentication for overrides |
Policy-Driven Enforcement¶
Beyond identity verification, CapiscIO supports YAML-based policy configurations that define trust requirements, access rules, and rate limits. Policies are scoped at three levels:
- Organization: Baseline rules for all agents
- Group: Rules for named collections of agents
- Agent: Per-agent overrides for fine-grained control
See Policy Scoping for the full scoping model, or Configure Agent Policy for a practical walkthrough.