Network-AI
Security

Threat Model

Adversary model, trust boundaries, protected assets, and explicit non-goals for Network-AI as an in-process multi-agent orchestrator.

Source file: THREAT_MODEL.md

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

AssetSensitivityDescription
Blackboard stateHighShared agent memory; controls agent behaviour
Audit logHighTamper-evident event record; forensics + compliance
Permission tokensHighGrant-tokens authorise resource access
HMAC signing keyCriticalSigns every grant token; compromise = token forgery
Agent trust registryMediumTrust levels that gate permission scoring
Environment configsMediumPer-env data directories and promotion chain
Budget stateLowToken/cost accounting; denial-of-service vector
Perpetual operator key (Ed25519)CriticalSigns renewal policies, guarded-path approvals, and budget policies; compromise = agents can be given any limits
Lease authority key (Ed25519)CriticalSigns leases; compromise = leases can be minted outside the policy
Lease role secrets (operator / sentry / runner)HighAuthenticate control-API callers; the operator secret can resume and install policies
Egress credentialsHighUpstream API and payment credentials held only by the egress proxy
Snapshot secret, pipeline keyHighSign blackboard snapshots and self-improvement receipts
Additional authority keys (k-of-n)CriticalEach co-signs leases; k of them together can issue leases within the signed policy
Merkle log keyHighSigns audit tree heads; compromise lets an attacker sign a forked head (witnesses still refuse inconsistent heads)
Evaluator keys, attestation keysHighSign capability evaluations and measurement quotes that gate high-risk leases
Decoy manifestMediumLists 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:

  • McpSseServer requires a non-empty secret; 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.
  • AuthGuardian scores 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.
  • ComplianceMonitor detects behavioural anomalies in real time.
  • ShellExecutor runs commands with spawn(shell: false) using a parsed argv; SandboxPolicy rejects unquoted shell metacharacters before the allowlist match, so a scoped allow such as git * 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:

  • BlackboardValidator enforces JSON Schema on all values.
  • InputSanitizer strips 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/; clear data/ 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 --yes flag 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 LeaseAuthority under an operator-signed policy; the agent holds only the authority's public key, so it cannot mint or extend a lease. LeaseGuard halts 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: GuardedPaths blocks 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 sentryQuorum keeps 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 an acceptRisk entry. 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; VsockRelay accepts 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-goalRationale
Protection against root/OS-level accessIf the attacker owns the process or OS, all file-based protections are void.
Encryption of blackboard data in transit between processes on the same hostIPC on localhost is assumed trusted.
Protection against a malicious Node.js require() hookPre-loaded modules run before any of our code.
SLA guarantees for operator-hosted deploymentsNetwork-AI is a library; the operator's SLA is their own.
Anti-analysis / obfuscationOpen source; security through obscurity is not a goal.
Protection against a compromised npm registry without provenance verificationOperators must verify provenance (npm audit signatures).
Confidentiality of blackboard values from the process ownerValues are stored as plaintext JSON on the local filesystem.

6. Security Controls Summary

ControlWhereAddresses
Fail-closed MCP auth (SSE)lib/mcp-transport-sse.tsAdversary 3.1
Fail-closed MCP auth (Streamable HTTP)lib/mcp-transport-http.tsAdversary 3.1
propose → validate → commitlib/locked-blackboard.tsAdversary 3.2
AuthGuardian weighted scoringlib/auth-guardian.tsAdversary 3.2
Shell-free command execution (shell: false + metacharacter rejection)lib/agent-runtime.tsAdversary 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.tsAdversary 3.2
Full-target deny/allow pattern matching (no truncation before the security decision — GHSA-743h-jr5x-mpcr)lib/claude-hooks.tsAdversary 3.2
Justification hardeninglib/auth-guardian.tsAdversary 3.2, 3.3
BlackboardValidator schemalib/blackboard-validator.tsAdversary 3.3
InputSanitizersecurity.tsAdversary 3.3
HMAC-signed grant tokensscripts/check_permission.pyAdversary 3.2
npm provenance / SLSACI pipelineAdversary 3.4
Append-only audit logsecurity.tsAdversary 3.5
ComplianceMonitorlib/compliance-monitor.tsAdversary 3.2
ClaimVerifier — Tier 1 agent honestylib/claim-verifier.tsAdversary 3.2
Rate limitingsecurity.tsAll
Path traversal protectionscripts/blackboard.pyAdversary 3.5
Out-of-process lease authority + dead-man switchlib/perpetual/lease-authority.ts, lease-guard.tsAdversary 3.6
Credential-holding egress proxy with lease, scope, rate, and financial limitslib/perpetual/egress-proxy.tsAdversary 3.6
Guarded governance paths (operator-signed, content-bound, single-use approvals)lib/perpetual/guarded-paths.tsAdversary 3.2, 3.6
Disposable gVisor sandboxlib/perpetual/sandbox.tsAdversary 3.2, 3.6
Sentry swarm with authenticated identities and quorumlib/perpetual/sentry.tsAdversary 3.2, 3.3, 3.6
Self-improvement receipts bound to the patch hashlib/perpetual/improvement-pipeline.tsAdversary 3.6
Signed, hash-chained snapshots and canary rollbacklib/perpetual/self-healing.tsAdversary 3.3, 3.6
Lower-only budget ceilings, approved sources onlylib/perpetual/budget-balancer.tsAdversary 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: 0 when the command actually failed; detected because tampering with any receipt field (including exitCode or outputHash) invalidates the HMAC signature.
  • Undisclosed actions — agent executes something without declaring it in its manifest; detected by diffing the AgentRuntime audit 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 agentId inside 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:

  1. 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. Converts ShellExecutor/FileAccessor from a convention into the only possible path.
  2. CapabilityBroker — privileged parent holds the only real fs/proc handles; sandbox communicates via IPC only.
  3. 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 clear data/ 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.