Security posture

Honest. Localhost-only. Experimental. No compliance claims.

IRIN is a local-first, single-operator product: structured multi-model deliberation on macOS and Ubuntu, with an optional governed Gateway and a separate Sentinel/Watch lane. Everything binds to 127.0.0.1 by default. Direct provider transport is the default; Gateway is explicit per-seat opt-in. The Watch producer and dispatcher are off by default. It is experimental and makes no compliance, certification, or conformance claims of any kind.

Default-off, localhost stance

All network surfaces default to loopback. Council, War Room Web, and Gateway bind loopback in the canonical runtime. Compose publishes Gateway only as 127.0.0.1:18080:8080 (demo equivalents on 28080). The watch-plane components that turn observation into pending escalations are disabled at startup: WATCH_DISPATCHER_ENABLED=${WATCH_DISPATCHER_ENABLED:-false} and WATCH_PRODUCER_ENABLED=${WATCH_PRODUCER_ENABLED:-false}.

Loading or enabling a Sentinel is not arming. Arming the Gateway Watch producer is a ceremony, not a flag flip. It requires dual custody (host bearer token list GW_ARM_PRINCIPALS plus hardware-backed attest) and still performs writer-claim checks and appends to arm_audit. After any live proof the loop flags are reset to default-OFF. The interactive path is a hardware ceremony (Secure Enclave / FIDO2 tap); a boot env path exists that is an audited config flip — it can start watchers but cannot claim, spend, or sign a new directive without a hardware-attested arm.

Direct vs Gateway

Council calls provider APIs and authenticated local CLIs directly unless a seat is explicitly set to Governed via Gateway. Gateway adds metering, budget limits, and a signed audit-ledger record for that call. Spend limits on Gateway paths do not constrain Direct calls. Outside Gateway, provider spend is unconstrained by IRIN.

Signed directives (Ed25519 over RFC 8785 JCS)

On the Watch→Outbox lane, Council emits a Directive naming job, scope, stop condition, and return expectation. Gateway serializes it with the sovereign-protocol RFC 8785 JCS canonicalizer, signs the canonical bytes with its Ed25519 private key, and writes both the canonical JSON and the signature into a row in directive_outbox. Any later reader can recompute the JCS form and verify the signature against the public key. An ordinary War Room run does not create this row.

Ed25519 + JCS provides verifiability (deterministic canonical form independent of encoder whitespace or ordering) and custody (the signed row is the durable record that the decision crossed the deliberation boundary under the operator's key).

Three distinct signed surfaces

watch_fires carries the hash chain (SHA-256) so tampering with prior fire rows is detectable. directive_outbox stores individually signed Directive envelopes (per-row Ed25519) — not a hash-chained table. The governed Gateway audit ledger is a separate signed ledger for routing, accounting, and decontaminator events on governed paths. Do not conflate these three.

The signing public key is served without auth at /watch/outbox/pubkey; outbox row reads and all mutations require an authenticated key (unauthenticated requests get 401).

Budget caps

The ≤120 s budget is the closed-loop triage envelope only (WATCH_DISPATCHER_COUNCIL_TIMEOUT_SECS default). Interactive War Room and bare CLI sessions run on the operator's clock. On Gateway-governed paths, spend is metered with atomic reserve-settle-or-rollback; daily caps and per-directive ceilings act as hard ceilings enforced before spend.

What we explicitly do NOT claim
  • No SOC 2, ISO/IEC 42001, NIST conformance, CISA/NSA validation, EU AI Act compliance, or any certification.
  • No multi-tenant isolation guarantees (operation is single-operator and local-first).
  • No claim that model output is correct or that a Directive will be executed.
  • No claim that every call crosses Gateway, or that every action is recorded or executed.
  • No claim that the surrounding deployment is safe for public or LAN exposure.
  • Host compromise (root or same-uid) can read on-disk signing materials and forge verifiable rows on surfaces whose private key material is present. Hash chains provide tamper-evidence, not prevention.
  • No autonomous operator-ready Worker ships. Authenticated worker-management routes may be mounted; the built-in worker loop is disabled by default and is not an operator-ready executor. Product guidance ends at the signed Outbox directive.
  • Ephemeral workers and a tenant librarian are not current IRIN product primitives.
  • Critical-infrastructure-grade assurance is out of scope. Protection from host compromise is not provided.

Acknowledged gaps (today)

Memory & context poisoning: The precedent store and other retrieved context are not yet watched by integrity sentinels. Hash chains protect the fire log; outbox rows are individually signed; neither protects model context.

Sequence-level / multi-step attacks: Single-step policy, fences, and budgets exist on governed paths. There is no stateful sequence watcher over chains of actions yet.

Reporting a vulnerability

Please do not report security vulnerabilities through public GitHub issues.

Report privately to [email protected] or via GitHub Security Advisories ("Report a vulnerability" under the Security tab on the repository).

Include a description of the vulnerability, steps to reproduce, and any relevant logs, ledger/verify output, or traces. Coordinated disclosure is expected.