Chio/Docs

Guards Spec

The conformance reference for the Chio guard taxonomy: pipeline ordering, fail-closed semantics, verdicts, evidence, advisory promotion, post-invocation hooks, WASM custom guards, and the session journal contract that session-aware guards read from.

Source

This page normatively reflects spec/GUARDS.md in the chio repository. Status: Normative. Version 1.0. The keywords MUST, SHOULD, and MAY are normative per RFC 2119.

Narrative coverage

This page is the conformance reference. For narrative coverage of the guard platform (motivation, integration, operator guidance), see guard-platform docs.

Guard Pipeline Overview

The Chio runtime kernel evaluates guards in a sequential pipeline before admitting any tool invocation. Guards produce GuardEvidence entries that attach to the signed receipt for the invocation, providing an auditable record of which guards evaluated the request and what they observed.

Guard Categories

CategoryStatePhaseBlocking
Stateless deterministicNonePre-invocationYes
Session-aware deterministicSession journalPre-invocationYes
Post-invocation hooksTool responsePost-invocationYes
Advisory signalsSession journal (optional)Pre-invocationNo (unless promoted)
WASM custom guardsSandboxed runtimePre-invocationConfigurable

Evaluation Order

Guards SHOULD be evaluated in the following order within the pipeline:

  1. Stateless deterministic guards (cheapest, no I/O).
  2. Session-aware deterministic guards (require journal read).
  3. WASM custom guards (sandboxed execution, potentially expensive).
  4. Advisory pipeline (non-blocking signals, evaluated last for observability).

Post-invocation hooks run after the tool produces a response but before delivery to the agent.


Fail-Closed Semantics

The pipeline operates under a universal fail-closed invariant:

  • If any guard returns Deny, the pipeline MUST short-circuit and deny the request.
  • If any guard returns an error (including internal panics, lock poisoning, or serialization failures), the pipeline MUST treat the request as denied.
  • Only when every guard in the pipeline returns Allow is the request admitted.

Per-guard fail-closed obligations are listed under each guard below. See guard-platform: fail-closed for narrative discussion.


Verdict

Guards return one of three verdicts at the pipeline level. The spec-level verdict vocabulary is Allow, Deny, and PendingApproval.

VerdictEffect
AllowAdmit the request to the next pipeline stage; if all guards allow, dispatch to the tool server.
DenyShort-circuit the pipeline. The kernel emits a signed denial receipt and returns the deny envelope.
PendingApprovalThe request requires human-in-the-loop approval before admission. The kernel records the pending state on the receipt; resolution is out-of-band.

Evidence Accumulation

Guards emit GuardEvidence entries that the kernel attaches to the signed receipt. The accumulated evidence is the auditable trail that lets operators and downstream consumers see which guards evaluated the request and what they observed.

GuardOutput

The GuardOutput type provides a unified representation of guard results in the evidence array. The type discriminator field uses snake_case in JSON serialization.

VariantTagFieldsDescription
Deterministic"deterministic"guard_name, verdict (bool), detailsResult from a standard guard
Advisory"advisory"All AdvisorySignal fieldsNon-blocking observation

Stateless Deterministic Guards

Stateless deterministic guards inspect only the current request context (tool name, arguments, agent identity, capability scope). They require no external state, no session history, and no I/O. Their verdicts are reproducible given the same inputs.

InternalNetworkGuard

Guard name: internal-network. Prevents Server-Side Request Forgery (SSRF) by blocking network egress to private, reserved, and cloud infrastructure addresses. Critical for the HTTP substrate where agents may attempt to reach internal services through tool invocations.

Blocked address classes:

ClassRangeRationale
RFC 1918 (Class A)10.0.0.0/8Private networks
RFC 1918 (Class B)172.16.0.0/12Private networks
RFC 1918 (Class C)192.168.0.0/16Private networks
Loopback (IPv4)127.0.0.0/8Host-local services
Loopback (IPv6)::1Host-local services
Link-local (IPv4)169.254.0.0/16Auto-configured addresses
Link-local (IPv6)fe80::/10Neighbor discovery scope
Unique local (IPv6)fc00::/7Private IPv6 ranges
Cloud metadata169.254.169.254, metadata.google.internal, metadata.azure.comCloud instance credentials
Kuberneteskubernetes.default.svc, kubernetes.defaultCluster-internal APIs
Broadcast255.255.255.255Network broadcast
Current network0.0.0.0/8Ambiguous origin
IPv4-mapped IPv6::ffff:<private-v4>Bypass via address format

DNS rebinding detection blocks hostnames that embed private IP patterns using dash or dot separators (e.g., evil.127-0-0-1.attacker.com). Encoded IP detection blocks hostnames that appear to be obfuscated IP addresses in hexadecimal, decimal, or octal notation.

Fail-closed

Any IP parse error, ambiguous address, or unexpected format MUST result in denial. Only addresses that are unambiguously public are allowed. Requests that do not involve network egress (file reads, shell commands) MUST pass through this guard without evaluation; the guard only activates for NetworkEgress actions.

AgentVelocityGuard

Guard name: agent-velocity. Enforces per-agent and per-session rate limits using token-bucket semantics. Unlike the grant-scoped VelocityGuard, this guard rate-limits by agent identity across all capabilities, preventing a single agent from overwhelming the system regardless of how many capabilities it holds. Token-bucket arithmetic uses integer milli-tokens to avoid floating-point drift.

BucketKeyPurpose
Per-agentagent_idCross-capability rate limit for a single agent
Per-session(agent_id, capability_id)Rate limit within a single session/capability context

When both limits are configured, both MUST pass for the request to be allowed; the stricter limit takes effect. If the internal mutex is poisoned, the guard MUST return KernelError::Internal, which the pipeline treats as a denial.


Session-Aware Deterministic Guards

Session-aware deterministic guards consult the session journal to make decisions based on cumulative session history. They require an Chio<SessionJournal> reference and produce deterministic verdicts given the same journal state.

DataFlowGuard

Guard name: data-flow. Enforces cumulative data transfer limits per session, preventing data exfiltration through many small requests that individually appear benign but cumulatively transfer large volumes. The guard reads cumulative bytes_read and bytes_written from the session journal's CumulativeDataFlow snapshot. Limits are checked against running totals, not per-request deltas.

OptionTypeDefaultDescription
max_bytes_readu64 or nullnull (unlimited)Maximum cumulative bytes read per session
max_bytes_writtenu64 or nullnull (unlimited)Maximum cumulative bytes written per session
max_bytes_totalu64 or nullnull (unlimited)Maximum cumulative bytes (read + written) per session

If the session journal is unavailable (lock poisoned, I/O error), the guard MUST return an error, which the pipeline treats as a denial. The guard MUST NOT default to allow when journal state is inaccessible.

BehavioralSequenceGuard

Guard name: behavioral-sequence. Enforces tool ordering policies to prevent dangerous sequences. The guard reads the tool invocation sequence from the session journal and checks four constraint types:

ConstraintDescription
Required predecessorsTool X MUST NOT run unless tools Y and Z have been invoked earlier in the session
Forbidden transitionsTool X MUST NOT run immediately after tool Y
Max consecutiveThe same tool MUST NOT run more than N times consecutively
Required first toolThe first tool in a session MUST match a specified name

If the session journal is unavailable, the guard MUST return an error, which the pipeline treats as a denial.


Post-Invocation Hooks

Post-invocation hooks run after a tool produces a response but before that response is delivered to the agent. They inspect response content and can modify, block, or escalate it.

PostInvocationPipeline

The pipeline evaluates hooks in registration order. Each hook returns one of four verdicts:

VerdictEffect
AllowResponse passes through unmodified
Block(reason)Response is replaced with an error message; pipeline short-circuits
Redact(value)Response content is replaced with the redacted version; subsequent hooks see the redacted version
Escalate(message)Response is delivered, but an escalation signal is emitted for operator review

Pipeline semantics:

  • A Block from any hook MUST stop the pipeline immediately. No subsequent hooks run.
  • A Redact replaces the response for all subsequent hooks. Multiple Redact hooks compose sequentially.
  • Escalate messages are collected throughout the pipeline and reported alongside the final verdict.
  • If no hooks modify the response, the final verdict is Allow.

ResponseSanitizationGuard

Guard name: response-sanitization. Scans tool responses (and request arguments when used pre-invocation) for PII and PHI patterns, then blocks or redacts matches before the data reaches the agent.

PatternExampleSensitivityRedaction
SSN123-45-6789High[SSN REDACTED]
Emailuser@example.comMedium[EMAIL REDACTED]
Phone(555) 123-4567Low[PHONE REDACTED]
Credit card4111-1111-1111-1111High[CARD REDACTED]
Date of birth1990-01-15 or 01/15/1990Low[DATE REDACTED]
MRNMRN: 123456789High[MRN REDACTED]
ICD-10J18.9, E11Medium[ICD REDACTED]

The min_level configuration controls the minimum sensitivity threshold; only patterns at or above the threshold trigger the guard. Operators MAY define custom patterns via build_pattern() with name, regex, sensitivity level, and redaction string. Invalid regexes are silently skipped at load time.

Dual-phase operation:

  • Pre-invocation: scans request arguments for PII that should not be sent to tool servers; denies if patterns are found.
  • Post-invocation: scan_response returns ScanResult::Clean, ScanResult::Blocked, or ScanResult::Redacted.

Advisory Pipeline and Promotion

Advisory signals are non-blocking observations emitted during guard evaluation. They provide operators with visibility into request patterns without affecting the verdict, unless explicitly promoted.

AdvisorySignal

FieldTypeDescription
guard_namestringName of the advisory guard that produced the signal
descriptionstringHuman-readable observation
severityAdvisorySeveritySeverity classification
metadataobject or nullStructured metadata about the observation
promotedbooleanWhether this signal was promoted to a deterministic denial (set by the promotion policy, not the guard)

Advisory signals are serialized and attached to the receipt as part of the GuardOutput evidence array. They MUST be included in the signed receipt body so that auditors can review all observations.

Severity Levels

LevelOrdinalMeaning
Info0Informational observation, no action needed
Low1Worth monitoring over time
Medium2May warrant investigation
High3Likely needs operator attention
Critical4Strong signal of abuse or anomaly

Severity levels are ordered. A promotion rule with min_severity: Medium promotes signals at Medium, High, and Critical.

AdvisoryPipeline Behavior

The AdvisoryPipeline wraps multiple AdvisoryGuard implementations and a PromotionPolicy. It implements the kernel's Guard trait so it can register in the standard pipeline. Guard name: advisory-pipeline.

  1. The pipeline evaluates every registered advisory guard in order.
  2. Each guard returns zero or more AdvisorySignal entries.
  3. For each signal, the pipeline checks the promotion policy.
  4. If any signal matches a promotion rule, it is marked promoted: true and the pipeline returns Verdict::Deny.
  5. If no signals are promoted, the pipeline returns Verdict::Allow.
  6. All collected signals (promoted or not) are stored for evidence export.

Without any promotion rules, the advisory pipeline MUST always return Verdict::Allow.

PromotionPolicy

Operators configure promotion rules in chio.yaml to convert advisory signals into deterministic denials:

chio.yaml
advisory:
  promotion_rules:
    - guard_name: anomaly-advisory
      min_severity: high
    - guard_name: data-transfer-advisory
      min_severity: critical
PromotionRule fieldTypeDescription
guard_namestringExact match on the advisory guard's name
min_severityAdvisorySeverityMinimum severity to promote

When a signal matches a promotion rule (guard name matches and signal severity is at least the rule severity), the signal's promoted field is set to true and the pipeline returns Deny. Both PromotionRule and PromotionPolicy serialize via serde with snake_case severity values.

Built-in Advisory Guards

AnomalyAdvisoryGuard (anomaly-advisory): flags unusual invocation patterns and excessive delegation depth.

ConditionSeverityDescription
Tool invoked >= threshold timesMediumTool X invoked N times (threshold: T)
Tool invoked >= 2x thresholdHighElevated severity for sustained repetition
Delegation depth >= thresholdHighDelegation depth D exceeds threshold T

DataTransferAdvisoryGuard (data-transfer-advisory): flags sessions with high cumulative data transfer, useful as an early warning before the deterministic DataFlowGuard limit is hit.

ConditionSeverityDescription
Total bytes >= thresholdMediumCumulative transfer exceeds threshold
Total bytes >= 2x thresholdHighElevated severity
Total bytes >= 3x thresholdCriticalCritical data volume

Signals include total_bytes, bytes_read, bytes_written, and threshold in metadata. See guard-platform: advisory.


WASM Custom Guards

The chio-wasm-guards crate allows operators to author guards in any language that compiles to WebAssembly (Rust, AssemblyScript, Go, C) and load them into the Chio kernel at runtime.

Host-Guest ABI

Each .wasm guard module MUST export a single function:

rust
evaluate(request_ptr: i32, request_len: i32) -> i32

The host serializes a GuardRequest as JSON, writes the bytes into guest linear memory at offset 0, and calls evaluate(0, json_length). Return codes:

CodeMeaning
0Allow
1Deny
Any negative valueError (fail-closed)

The guest MAY write a NUL-terminated UTF-8 deny reason starting at offset 65536 (64 KiB) in linear memory; the host reads up to 4096 bytes. If the region is absent, empty, or malformed, the host uses a generic denial message.

GuardRequest

FieldTypeDescription
tool_namestringTool being invoked
server_idstringServer hosting the tool
agent_idstringAgent making the request
argumentsobjectTool arguments (opaque JSON)
scopesstring[]Granted scope names (formatted as "server_id:tool_name")
session_metadataobject or nullOptional session context for stateful guards

Fuel Metering

WASM guards execute under a fuel budget that limits CPU consumption. The runtime tracks fuel consumption per instruction and terminates the guest when the budget is exhausted. Default fuel_limit: 10,000,000 units per invocation.

Fail-closed on every error

When fuel runs out, the runtime MUST terminate the guest and treat the invocation as denied (WasmGuardError::FuelExhausted). Any WASM trap (memory access violation, stack overflow, unreachable instruction) MUST result in denial. If the module does not export the required evaluate function or memory, the load MUST fail and the guard MUST NOT be registered in the pipeline.

Configuration

chio.yaml
wasm_guards:
  - name: custom-pii-guard
    path: /etc/chio/guards/pii_guard.wasm
    fuel_limit: 5000000
    priority: 100
    advisory: false

When advisory: true, the guard logs denials and errors but returns Verdict::Allow. This lets operators test new WASM guards in production without blocking traffic.

Security Properties

  • Sandboxed execution: WASM guards execute in an isolated linear memory space with no access to the host filesystem, network, or kernel state.
  • Deterministic termination: fuel metering guarantees that guards terminate within bounded time.
  • No host callbacks: the current ABI does not provide any host functions to the guest. The guest can only read the provided request and return a verdict.
  • Fail-closed on all errors: compilation failure, missing exports, fuel exhaustion, traps, and unexpected return values all result in denial (for non-advisory guards).

Session Journal Contract

The session journal (chio-http-session crate) is the shared state layer that session-aware guards and advisory guards read from. It is an append-only, hash-chained log of request records within a single session.

Invariants

  • Append-only: entries MUST only be added, never modified or removed.
  • Hash-chained: each entry MUST include a SHA-256 hash of the previous entry for tamper detection. The first entry uses the zero hash (64 hex zeros) as its prev_hash.
  • Thread-safe: the journal MUST be safe for concurrent access from multiple guards. The implementation uses a Mutex around the inner state.
  • Per-session scope: each session creates one journal, shared via Chio<SessionJournal> with all guards that need it.

Journal Entry

FieldTypeDescription
sequenceu64Monotonically increasing sequence number (0-based)
prev_hashstringSHA-256 hex hash of the previous entry (zero hash for the first entry)
entry_hashstringSHA-256 hex hash of this entry's canonical fields
timestamp_secsu64Unix timestamp (seconds) when the entry was recorded
tool_namestringTool that was invoked
server_idstringServer that hosted the tool
agent_idstringAgent that made the invocation
bytes_readu64Bytes read during this invocation
bytes_writtenu64Bytes written during this invocation
delegation_depthu32Delegation depth at the time of invocation
allowedbooleanWhether the invocation was allowed or denied

Entry hash computation: the entry_hash is the SHA-256 digest of the fields concatenated in this order using little-endian byte encoding for integers and UTF-8 for strings:

  1. sequence (8 bytes, LE)
  2. prev_hash (UTF-8 bytes)
  3. timestamp_secs (8 bytes, LE)
  4. tool_name (UTF-8 bytes)
  5. server_id (UTF-8 bytes)
  6. agent_id (UTF-8 bytes)
  7. bytes_read (8 bytes, LE)
  8. bytes_written (8 bytes, LE)
  9. delegation_depth (4 bytes, LE)
  10. allowed (1 byte: 0x01 for true, 0x00 for false)

Cumulative Accounting

The journal maintains running cumulative statistics that guards read via data_flow(): total_bytes_read, total_bytes_written, total_invocations, and max_delegation_depth. All additions use saturating arithmetic to prevent overflow.

Integrity Verification

The verify_integrity() method walks the hash chain and verifies:

  1. Each entry's prev_hash matches the preceding entry's entry_hash (or the zero hash for the first entry).
  2. Each entry's entry_hash matches the recomputed hash of its canonical fields.

If either check fails, the journal returns SessionJournalError::IntegrityViolation with the index, expected hash, and actual hash. Operators SHOULD invoke integrity verification at session boundaries or during audit. Guards MAY verify integrity before reading journal state, though this adds latency and is not required for normal operation.

Guard Access Patterns

GuardJournal methodUsage
DataFlowGuarddata_flow()Read cumulative byte counts
BehavioralSequenceGuardtool_sequence()Read ordered tool history
AnomalyAdvisoryGuardtool_counts(), data_flow()Read per-tool counts and delegation depth
DataTransferAdvisoryGuarddata_flow()Read cumulative byte counts

Implementation Status

GuardCrateStatus
InternalNetworkGuardchio-guardsFull
AgentVelocityGuardchio-guardsFull
DataFlowGuardchio-guardsFull
BehavioralSequenceGuardchio-guardsFull
ResponseSanitizationGuardchio-guardsFull
PostInvocationPipelinechio-guardsFull
AdvisoryPipelinechio-guardsFull
AnomalyAdvisoryGuardchio-guardsFull
DataTransferAdvisoryGuardchio-guardsFull
WasmGuardchio-wasm-guardsFull
WasmGuardRuntimechio-wasm-guardsFull
SessionJournalchio-http-sessionFull

Conformance Fixtures

The spec does not enumerate dedicated conformance fixtures here. Guard behavior is verified through the runtime test suites in each guard crate and through the broader Chio conformance scenarios; see the protocol-level conformance evidence under tests/conformance/ in the chio repository for the cross-cutting fixture set. Operators validating a guard configuration SHOULD pair guard configuration changes with replay-based verification using the kernel's signed receipts as ground truth.


Guards Spec · Chio Docs