Threat Model

!!! warning “Mermaid diagrams require JavaScript” Diagrams on this page use Mermaid rendered via sphinxcontrib-mermaid. They require JavaScript to be enabled and, in non-air-gapped environments, an outbound connection to cdn.jsdelivr.net (pinned to mermaid.js 10.2.0 via mermaid_version in docs/conf.py). In air-gapped deployments, host mermaid.min.js locally and update mermaid_version in docs/conf.py to point to the local path.

Note: This page documents currently implemented and tested threat boundaries. It is intentionally scoped to evidence available in repository code/tests and generated outputs.

Trust Boundary

The runtime is the sole policy authority. Adapters are untrusted callers:

flowchart LR subgraph UZ["Untrusted zone"] A1["Python adapter"] A2["LangChain tool"] A3["Any HTTP client"] end RT["Go runtime<br/>(trusted zone)"] PE["policy evaluation (OPA/Rego)"] AL["Allow → tool execution"] DE["Deny → HTTP 403"] A1 -->|"POST /v1/tool"| RT A2 -->|"POST /v1/tool"| RT A3 -->|"POST /v1/tool"| RT RT --> PE PE --> AL PE --> DE

Adapters submit tool-call intents via POST /v1/tool. The runtime evaluates the active policy bundle and either:

  • Allows — executes the tool and returns {decision:"allow", output:...}

  • Denies — returns HTTP 403 with {decision:"deny", reason:...}

No adapter code path can flip Deny to Allow. This invariant is tested in runtime/interceptor_test.go:TestInterceptorDenyCannotBeOverridden.

Trust Boundary Diagram

graph LR A[Python adapter<br>LangChain / custom] -->|POST /v1/tool<br>untrusted| B[Go runtime<br>ToolServer] B -->|policy eval| C[OPA evaluator<br>active bundle] C -->|Allow| D[Tool execution] C -->|Deny: HTTP 403| E[PolicyDeniedError] B ---|mTLS only| F[Peer node<br>segment relay] G[Control plane] ---|HTTPS poll| B

Fail-Closed Design

The runtime is designed to fail closed under every degraded condition:

Condition

Behaviour

Policy evaluator returns error

Default: Deny

No active policy bundle loaded

denyAllEvaluator{} — deny all tool calls

Corrupt or incompatible bundle

Fall back to LKG bundle; if no LKG, deny-all

OCI cosign verification fails

Release rejected; no activation; lifecycle event emitted

Control-plane unreachable

Local cache serves decisions; no degradation to allow-all

Tests: TestInterceptorDenyCannotBeOverridden, TestInterceptorFailClosed in runtime/.

Protected Assets

Asset

Description

Protection

A-01

Local segment store integrity

Disk ceiling (INV-04) + fsync before ack

A-02

Policy bundle authenticity

Cosign signature (Step 1) + bundle hash

A-03

Agent artifact identity

OCI digest match (Step 2) + behavioral fingerprint (Step 3)

A-04

Decision authority

Runtime fail-closed; deny-all fallback; adapters cannot override

A-05

Peer identity

mTLS required for all segment exchange (INV-09)

Hash Algorithm Assignments

Two hash algorithms are used with distinct, non-interchangeable roles:

Field / purpose

Algorithm

Prefix

Source

behavioral_fingerprint

BLAKE3

blake3:

lock.ComputeFingerprint — computed over canonical JSON lock bytes

agent_artifact.digest

SHA-256

sha256:

OCI registry manifest

policy_bundle.digest

SHA-256

sha256:

OCI registry manifest

inputs.prompt_hash

SHA-256 or BLAKE3

caller-specified

Caller-supplied

Policy bundle_hash

SHA-256

sha256:

policy.Build

!!! danger “Never substitute BLAKE3 for SHA-256 or vice versa” behavioral_fingerprint is always BLAKE3. OCI digests are always SHA-256. Mixing them produces a fingerprint mismatch at Step 3 of the verification pipeline.

See Contracts for the full hash-role reference table.

Adversary Capabilities

Current documented non-goals:

Non-Goal

Rationale

Byzantine consensus defence

No consensus protocol exists (INV-02)

RF jamming defence

Physical layer outside scope

Infinite resource saturation

Bounded by INV-04/INV-07/INV-13; not a security guarantee

Beacon-based peer authorisation

Beacon is unauthenticated by design; see Beacon Privacy

Security Invariant Mapping

Threat

Mitigating Invariant(s)

Enforcement

Shared-storage compromise

INV-01 (No Shared State)

Startup path check + edge/ci/scan_prohibited

Distributed coordination attack

INV-02, INV-03

edge/ci/scan_prohibited

Disk exhaustion DoS

INV-04 (Disk Ceiling)

statfs check + eviction + FI-C1-01

Unauthenticated peer exchange

INV-09 (Authorization Boundary)

mTLS + CRL; FI-C3-02

Mission-layer privilege escalation

INV-10 (Decoupling)

edge/ci/scan_dependencies

Retry amplification attack

INV-12 (Bounded Retry)

Monotonic counter; FI-C4-01

Per-peer bandwidth exhaustion

INV-13 (Bounded Quota)

Token bucket; FI-C3-03

Security Acceptance Criteria

From Workplan v0.6 §9.2 (tracked here for Phase 3 completion):

  • Trust boundaries documented: control-plane vs runtime-plane vs adapters vs peer nodes

  • Key material handling: cosign keys, mTLS certs — storage and rotation documented

  • Beacon non-auth stance: beacon-privacy.md explains discovery vs authorisation separation

  • Fail-closed verified: TestInterceptorDenyCannotBeOverridden, TestInterceptorFailClosed

  • All 4 cosign verification steps documented with tamper-test cross-references

Evidence

  • runtime/interceptor.go, runtime/interceptor_test.go

  • runtime/server.go, runtime/poller.go

  • policy/manager.go, policy/evaluator.go

  • oci/sign/verify.go, oci/sign/verify_tamper_test.go

  • edge/transport/tcptls.go, edge/transport/transport_test.go

  • edge/quota/localquota.go, edge/retry/retry.go

  • docs/_generated/test-outputs/demo-output.txt

Do Not Do

  • ❌ Do NOT trust adapter-supplied identity or role claims — policy is enforced by the runtime

  • ❌ Do NOT allow segment exchange before mTLS handshake completes (INV-09)

  • ❌ Do NOT use beacon data for peer authorisation — beacon is unauthenticated (see Beacon Privacy)

  • ❌ Do NOT use BLAKE3 for OCI digests or SHA-256 for behavioral_fingerprint — they are not interchangeable

See Also