Network-AI Threat Model
Version: 6.0.0 — updated with each release that changes a trust boundary or auth mechanism.
1. Overview
Network-AI is an in-process multi-agent orchestrator. There is no SaaS or cloud-hosted service — the operator installs it and runs it inside their own infrastructure. The package includes an optional MCP SSE server (bin/mcp-server.ts) that, when explicitly started by the operator, binds a TCP port and becomes a network-reachable service boundary. This document describes the adversaries we design against, the trust boundaries we enforce, and the explicit non-goals that bound the threat model.
2. Assets
| Asset | Sensitivity | Description |
|---|---|---|
| Blackboard state | High | Shared agent memory; controls agent behaviour |
| Audit log | High | Tamper-evident event record; forensics + compliance |
| Permission tokens | High | Grant-tokens authorise resource access |
| HMAC signing key | Critical | Signs every grant token; compromise = token forgery |
| Agent trust registry | Medium | Trust levels that gate permission scoring |
| Environment configs | Medium | Per-env data directories and promotion chain |
| Budget state | Low | Token/cost accounting; denial-of-service vector |
| Perpetual operator key (Ed25519) | Critical | Signs renewal policies, guarded-path approvals, and budget policies; compromise = agents can be given any limits |
| Lease authority key (Ed25519) | Critical | Signs leases; compromise = leases can be minted outside the policy |
| Lease role secrets (operator / sentry / runner) | High | Authenticate control-API callers; the operator secret can resume and install policies |
| Egress credentials | High | Upstream API and payment credentials held only by the egress proxy |
| Snapshot secret, pipeline key | High | Sign blackboard snapshots and self-improvement receipts |
| Additional authority keys (k-of-n) | Critical | Each co-signs leases; k of them together can issue leases within the signed policy |
| Merkle log key | High | Signs audit tree heads; compromise lets an attacker sign a forked head (witnesses still refuse inconsistent heads) |
| Evaluator keys, attestation keys | High | Sign capability evaluations and measurement quotes that gate high-risk leases |
| Decoy manifest | Medium | Lists honeytoken values; leaking it to agents lets them avoid the tripwires |
3. Adversaries
3.1 Unauthenticated Network Caller (primary MCP threat)
Who: Any process that can reach the TCP port where McpSseServer is bound — including SSRF on the same host, containers on a shared network, or remote clients when the operator binds to a non-loopback address.
Goal: Invoke MCP tools (config_set, agent_spawn, blackboard_write, token_create, etc.) without credentials.
Mitigations:
McpSseServerrequires a non-emptysecret;listen()hard-rejects on empty secret (v5.7.2, GHSA-r78r-rwrf-rjwp)._isAuthorized()fails closed: empty secret → deny (v5.7.2).- Default bind address is
127.0.0.1; explicit warning if binding to a non-loopback address. - All tool invocations are logged to
data/audit_log.jsonl.
3.2 Malicious / Compromised Agent
Who: A registered agent that has been compromised or is acting outside its intended role.
Goal: Write arbitrary data to the blackboard, escalate its trust level, forge tokens, or hijack another agent's goal.
Mitigations:
- All writes go through
propose → validate → commit; validators reject schema violations. AuthGuardianscores each request (justification 40 %, trust 30 %, risk 30 %); low-trust agents are denied high-risk operations.- Justification hardening rejects prompt-injection patterns, keyword stuffing, repetition, and structural incoherence.
- Agent trust levels are stored in
data/trust_levels.json; modifications are audit-logged. ComplianceMonitordetects behavioural anomalies in real time.ShellExecutorruns commands withspawn(shell: false)using a parsed argv;SandboxPolicyrejects unquoted shell metacharacters before the allowlist match, so a scoped allow such asgit *cannot be escaped into arbitrary execution (v5.11.0, GHSA-qw6v-5fcf-5666).
3.3 Blackboard Poisoning / Context Injection
Who: Any caller that can write to the blackboard and wants to influence subsequent agent reads.
Goal: Plant malicious instructions that a downstream agent will execute as if they were trusted system data.
Mitigations:
BlackboardValidatorenforces JSON Schema on all values.InputSanitizerstrips prompt-injection payloads from string values._validate_context()in Python scripts detects injection patterns before use.- SKILL.md warns operators: never store secrets in
data/; cleardata/between untrusted projects.
3.4 Supply Chain Attacker
Who: A dependency author, registry hijacker, or CI pipeline attacker.
Goal: Introduce malicious code into network-ai or its dependencies that executes in the operator's environment.
Mitigations:
- npm provenance attestation on every release (SLSA Build Level 2).
- Signed commits and version tags.
- Dependabot PRs for dependency updates with CodeQL re-scan on each PR.
- Minimal runtime dependency surface (see
SUPPLY_CHAIN.md). - No network calls in core library code (BYOC — bring your own client).
3.5 Insider / CLI Operator
Who: A developer or CI job with local filesystem access.
Goal: Bypass the blackboard's propose → validate → commit cycle, forge audit entries, or exfiltrate the signing key.
Mitigations:
- Audit log is append-only (no delete API); clearing requires explicit
--yesflag and is itself logged. - HMAC signing key is stored at
data/.signing_key; filesystem permissions are the operator's responsibility. - All CLI mutations are logged to the audit trail.
- Rate limiting prevents bulk-write abuse from CLI loops.
3.6 Self-Modifying, Long-Running Agent (Perpetual Runtime, v5.17.0+)
Who: A capable agent swarm running indefinitely with permission to improve its own code and spend money.
Goal: Keep running after a human wants it stopped, loosen its own limits (scope, ceilings, sentries, kill switch), acquire funding or compute on its own, or get a harmful patch applied.
Mitigations:
- I1 external stop: leases are issued by an out-of-process
LeaseAuthorityunder an operator-signed policy; the agent holds only the authority's public key, so it cannot mint or extend a lease.LeaseGuardhalts the run when the lease is revoked, paused, expired, or cannot be renewed (monotonic clock, so wall-clock rollback does not help). The egress proxy refuses every request without a live lease. - I2 limits stay fixed:
GuardedPathsblocks writes to governance files and keys without a single-use operator-signed approval of the exact content; the improvement pipeline sends guarded paths to the operator tier regardless of tests or consensus, and its receipts bind the exact patch hash. - I3 spend inside ceilings: ceilings come from the signed policy and are enforced by the authority (renewal stops at the ceiling; reported spend never decreases) and by financial egress routes (per-request and per-run caps) in the proxy process; agents can lower ceilings, never raise them or add sources.
- Sentries watch the audit stream read-only and can only alert or tighten; each has its own secret, and
sentryQuorumkeeps a single compromised sentry from stopping or steering runs. - Canary failures stop renewal, roll state back to the last verified (HMAC-signed, hash-chained) snapshot, and purge the session.
Residual risk: all of the above assumes the operator key, role secrets, and credentials stay outside the agents' reach, and that agents run in the sandbox with network access only through the proxy. An agent with unrestricted code execution on the host running the authority or proxy defeats these controls. Section 3.7 covers agents that may break out of the sandbox.
3.7 Zero-Day-Capable Agent (Perpetual Runtime Phase 5, v6.0.0+)
Who: An agent that obtains arbitrary code execution on its own machine and may find zero-days in the Node runtime, the guest kernel, or the hypervisor.
Goal: Escape the VM, reach the control plane, forge or extend leases, hide its traces.
Mitigations (see docs/hardened-deployment.md):
- I4 — the agent host cannot extend its run. Granting a lease needs signatures from k off-host authorities (
authorityQuorum,QuorumLeaseTransport,verifyLeaseQuorum). Every lease names its issuing authority; co-signers sign only claims carrying the issuer's valid signature, and verifiers require it, so the runner cannot assemble a lease from co-signatures. Each co-signer decides independently under the same signed policy, with its own run state, sequence numbers, stop conditions, and attestation checks. Stopping needs only one: any authority reporting a lease inactive makes guards and the proxy refuse it. High-risk policies require k ≥ 2 unless the operator signs anacceptRiskentry. Trusted tripwires and quorum sentry stops latch the authority until an operator resumes. - Off-host control (Z1): the posture gate (
perpetual doctor) refuses to start an authority or proxy that runs as the agent user or as root, has the operator key on its host, uses weak or shared secrets, or binds remotely without TLS. Authority keys can live in an HSM/KMS via--signer-cmd. - Minimal doors (Z2): microVM agents get no network interface;
VsockRelayaccepts four fixed, schema-checked, size-capped, rate-limited message types (plus egress) and never exposes admin routes. A one-way spool mode supports hardware data diodes. All doors are fuzzed (test-perpetual-fuzz.ts). - Tamper ⇒ stop (Z3): with
attestation, every renewal needs fresh evidence bound to a per-lease nonce with a listed measurement; a modified image cannot renew. - Bounded window (Z4): short leases, periodic operator-signed human checkpoints (
humanCheckpointEveryMs), honeytokens that revoke every run on use, and the hardened Node profile (no addons, no code generation, permission model) limit how long and how far an exploit chain can run. - Evidence before autonomy (Z5): gated high-risk scopes need a signed, passing, unexpired capability evaluation.
- Verifiable evidence: an RFC 9162 Merkle audit log with signed tree heads and a witness that refuses rollback and forks; claims carry inclusion proofs and are classified
proven | unproven | failed.
Residual risk: containment raises the cost of an attack and bounds its time; it does not make compromise impossible. Hypervisor, kernel, and hardware zero-days exist, and an attacker who controls k authority hosts can issue leases within the signed policy. The formal model in references/formal/ proves properties of the decision core's model only. Do not grant these modes to systems suspected of exceeding the containment's assurance.
4. Trust Boundaries
┌─────────────────────────────────────────────────────────────┐
│ Operator environment (filesystem, env vars, CLI) │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Network-AI process │ │
│ │ │ │
│ │ Agent code ──► AuthGuardian ──► Blackboard │ │
│ │ │ │ │ │ │
│ │ │ propose/validate/ │ │ │
│ │ │ commit cycle │ │ │
│ │ │ │ │ │
│ │ MCP SSE ──[bearer token]──► McpSseServer │ │
│ │ (TCP) │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ External callers ──[auth boundary]──► MCP SSE port │
└─────────────────────────────────────────────────────────────┘Boundary 1 — MCP network interface: Bearer token enforced by McpSseServer. Empty secret is a hard startup error. All calls are logged.
Boundary 2 — Agent → Blackboard: Mediated by AuthGuardian; weighted scoring gate. Agents cannot write directly to data/; they must go through LockedBlackboard.
Boundary 3 — Filesystem: data/ directory. The operator owns permissions on this directory. Network-AI applies path traversal protections (resolved-path boundary checks) but does not manage OS-level permissions.
Boundary 4 — Python scripts: Scripts in scripts/ run as a child process or standalone. They validate NETWORK_AI_ENV routing and apply HMAC signing to grant tokens. The signing key lives at data[/<env>]/.signing_key.
Boundary 5 — Perpetual Runtime control plane (opt-in): LeaseAuthority, EgressProxy, and sentries run as separate processes the agents cannot write to or signal. The authority and proxy bind loopback by default (non-loopback needs allowRemote and should sit behind TLS) and authenticate every control call with distinct role secrets in constant time. Agents reach the network only through the proxy, which holds the credentials.
Boundary 6 — Sandbox: with ISandboxRunner configured, each command runs in a disposable container (gVisor by default) with a read-only root, one writable workspace, no capabilities, and no network (or the egress network only).
5. Explicit Non-Goals
The following are outside the threat model — we do not design against them, and operators must address them at the infrastructure layer:
| Non-goal | Rationale |
|---|---|
| Protection against root/OS-level access | If the attacker owns the process or OS, all file-based protections are void. |
| Encryption of blackboard data in transit between processes on the same host | IPC on localhost is assumed trusted. |
| Protection against a malicious Node.js require() hook | Pre-loaded modules run before any of our code. |
| SLA guarantees for operator-hosted deployments | Network-AI is a library; the operator's SLA is their own. |
| Anti-analysis / obfuscation | Open source; security through obscurity is not a goal. |
| Protection against a compromised npm registry without provenance verification | Operators must verify provenance (npm audit signatures). |
| Confidentiality of blackboard values from the process owner | Values are stored as plaintext JSON on the local filesystem. |
6. Security Controls Summary
| Control | Where | Addresses |
|---|---|---|
| Fail-closed MCP auth (SSE) | lib/mcp-transport-sse.ts | Adversary 3.1 |
| Fail-closed MCP auth (Streamable HTTP) | lib/mcp-transport-http.ts | Adversary 3.1 |
propose → validate → commit | lib/locked-blackboard.ts | Adversary 3.2 |
| AuthGuardian weighted scoring | lib/auth-guardian.ts | Adversary 3.2 |
Shell-free command execution (shell: false + metacharacter rejection) | lib/agent-runtime.ts | Adversary 3.2 |
| Canonicalized command matching (blocklist/allowlist/approval/risk match the tokenized, quote-stripped form the executor runs — GHSA-9v4f-j8cv-fhxw) | lib/agent-runtime.ts | Adversary 3.2 |
| Full-target deny/allow pattern matching (no truncation before the security decision — GHSA-743h-jr5x-mpcr) | lib/claude-hooks.ts | Adversary 3.2 |
| Justification hardening | lib/auth-guardian.ts | Adversary 3.2, 3.3 |
| BlackboardValidator schema | lib/blackboard-validator.ts | Adversary 3.3 |
| InputSanitizer | security.ts | Adversary 3.3 |
| HMAC-signed grant tokens | scripts/check_permission.py | Adversary 3.2 |
| npm provenance / SLSA | CI pipeline | Adversary 3.4 |
| Append-only audit log | security.ts | Adversary 3.5 |
| ComplianceMonitor | lib/compliance-monitor.ts | Adversary 3.2 |
| ClaimVerifier — Tier 1 agent honesty | lib/claim-verifier.ts | Adversary 3.2 |
| Rate limiting | security.ts | All |
| Path traversal protection | scripts/blackboard.py | Adversary 3.5 |
| Out-of-process lease authority + dead-man switch | lib/perpetual/lease-authority.ts, lease-guard.ts | Adversary 3.6 |
| Credential-holding egress proxy with lease, scope, rate, and financial limits | lib/perpetual/egress-proxy.ts | Adversary 3.6 |
| Guarded governance paths (operator-signed, content-bound, single-use approvals) | lib/perpetual/guarded-paths.ts | Adversary 3.2, 3.6 |
| Disposable gVisor sandbox | lib/perpetual/sandbox.ts | Adversary 3.2, 3.6 |
| Sentry swarm with authenticated identities and quorum | lib/perpetual/sentry.ts | Adversary 3.2, 3.3, 3.6 |
| Self-improvement receipts bound to the patch hash | lib/perpetual/improvement-pipeline.ts | Adversary 3.6 |
| Signed, hash-chained snapshots and canary rollback | lib/perpetual/self-healing.ts | Adversary 3.3, 3.6 |
| Lower-only budget ceilings, approved sources only | lib/perpetual/budget-balancer.ts | Adversary 3.6 |
8. ClaimVerifier Scope and Limits (Tier 1 / Tier 2)
Tier 1 — What is built and enforced (v5.11.0+)
ClaimVerifier (lib/claim-verifier.ts) reconciles agent-declared action manifests against runtime-witnessed audit entries using outcome-bound signed receipts.
What it catches:
- Fabricated actions — agent claims it ran a command or wrote a file when it did not; detected by the absence of a valid signed receipt + matching audit entry.
- Fabricated/misrepresented outcomes — agent presents a tampered receipt claiming
exitCode: 0when the command actually failed; detected because tampering with any receipt field (includingexitCodeoroutputHash) invalidates the HMAC signature. - Undisclosed actions — agent executes something without declaring it in its manifest; detected by diffing the
AgentRuntimeaudit log against the manifest.
Trust consequences: N consecutive UNSUPPORTED_CLAIM violations (default: 3) decay the agent's trust score via AuthGuardian.registerAgentTrust(). Below the 0.4 threshold, requestPermission() denies high-risk resources and the agent is effectively gated behind ApprovalGate.
Scope ceiling (explicit, not hidden):
- Trusts that side effects route through
AgentRuntime(ShellExecutor/FileAccessor). BYOC adapter network calls are unmediated — a compromised adapter can make arbitrary outbound HTTP calls without a receipt. - Audit log is in-memory per session; verification is per-runtime-session, not cross-session or cross-process.
- Does not catch misleading interpretation of true outcomes (e.g.
exit 0→ "production-ready"). Receipt proves what ran and what the exit code was — not what it means. - Claim identity is cryptographically bound to
agentIdinside the signed receipt, so trust decay cannot be weaponised against a different agent.
Tier 2 — Hardening path for Adversary-3.2 deployments (not yet built)
For deployments where the threat model explicitly includes a compromised adapter making direct system calls:
- Child-process sandbox — run adapter/agent code in a separate OS process (not a worker thread) with Node's Permission Model stripping
--allow-child-process,--allow-fs-write,--allow-worker,--allow-addons. ConvertsShellExecutor/FileAccessorfrom a convention into the only possible path. CapabilityBroker— privileged parent holds the only real fs/proc handles; sandbox communicates via IPC only.- OS-level egress-deny — container/network namespace with default-deny egress; broker's unix socket is the only reachable endpoint. This is the only option that closes the BYOC network channel.
Until Tier 2 is deployed, operators running Adversary-3.2-grade workloads should run adapters in separate containers with egress controls at the infrastructure level.
Findings in the following categories will be acknowledged but closed as by-design:
- ASI01 — Agent goal hijack via LLM decomposition: the 3-subtask decomposition boundary is intentional; SKILL.md documents when to enable/disable.
- ASI03 — Advisory token identity: tokens are explicitly marked advisory; separate platform authentication is required.
- ASI06 — Persistent context poisoning:
_validate_context()injection detection is the mitigation; operators must cleardata/between untrusted projects. - ASI07 — Inter-agent communication boundary: all inter-agent messaging is the host platform's responsibility.
For active vulnerabilities, see SECURITY.md and the Security Advisories page.