Skip to content

Security model

The security architecture has three boundaries (cloud / Host / Device-local actor), four named operating postures (the policy presets), and one normative doctrine on where untrusted JavaScript is allowed to run (origin boundaries).

The three boundary diagram below explains what each tier is authoritative for. The four presets explain what the substrate is structurally allowed to do at this point in time. The origin doctrine explains which subjects can be served from which web origins. The three are independent axes; you have to think about all of them.

The three boundaries

text
+-------------------------+
|  HiveCast cloud         |  Authority for principal identity, OIDC IdP
|  (system-auth)          |  callbacks, namespace claims, Host Link
|                         |  records, principal-level credential storage.
|  - principal session JWT|
|  - external identity map|
|  - hostLinks[]          |
|  - publicNamespaces[]   |
|  - principal NATS account
|    seed (server-side)   |
+-------------------------+
            |
            | Pairing grant (the only legal bridge):
            |   device-scoped NATS user JWT/seed,
            |   heartbeat bearer token,
            |   non-secret link metadata.
            v
+-------------------------+
|  Local Host             |  Authority for runtime supervision, package
|  (host-service)         |  inventory, local NATS leaf, local HTTP
|                         |  gateway. Runs on the user's machine.
|  - host.json            |
|  - runtimes/*           |
|  - hivecast-link.json   |
|  - hivecast-nats.json   |
|  - hivecast-host-link-token
+-------------------------+
            |
            | Local credential lease/materialize:
            |   Factotum exposes credential.lease,
            |   trusted system actors call credential.materialize
            |   to get HTTP headers, never raw secrets.
            v
+-------------------------+
|  Device-local actors    |  Inference, drivers, package actors. Use
|                         |  credentials only via Factotum's lease/
|  - inference catalog    |  materialize discipline.
|  - chat, director, etc. |
+-------------------------+

What each boundary is authoritative for

HiveCast cloud: principal identity creation (Google/GitHub OIDC (iss, sub) -> principalId), browser sessions, namespace claim authority, Host Link issuance and revocation, principal-level credential storage, the principal's NATS account seed (NEVER copied to Devices).

Local Host: runtime supervision, local NATS configuration, local HTTP gateway routes, the Device's own copy of the link record + device-scoped credentials.

Device-local actors: their own logical state, anything they do via the bus, calls to third-party APIs only through Factotum's lease/materialize contract.

Operating postures (policy presets)

projects/matrix-3/packages/core/src/core/security/PolicyPresets.ts defines four presets:

PresetWhat it allowsWhen to use
devAllow everything (rules: [], default allow)Local development only. Hosted production must reject this preset.
standardAllow by default; explicit deny on factory.create-from-codeProduction baseline. Loads when policyEngine: 'declarative' and no explicit preset.
strictDeny by default; explicit allow for SYSTEM_OPS ($ping, $introspect, $join, $leave, $membrane, $getState, $getHistory, $createControl, $activity, $preferences, $config), agent/chat ops ($prompt, $response, $error, $cancelled), component lifecycle (component.list, component.get, $source-code), and introspection (introspect, snapshot.tree.oracle)Hosted/public control-plane posture. Use this when the Host is exposed to multi-tenant or untrusted callers.
lockdownDeny by default; allow only SYSTEM_OPSBootstrap or minimal mode. Useful during recovery.

The four presets compose the substrate's mode system. The product language local-dev / private-org / cloud-strict / marketplace-public maps onto these presets and policy extensions; it does not create a second security-mode system.

Status: target state — v0 acceptance. Hosted production must fail to boot if policyEngine is null or the selected preset is dev. The startup-time assertion is part of the v0 launch hygiene gate alongside P1.33/34/35. See thesis Part 4.5.

Preset names are not security proofs by themselves

A loaded strict preset does not by itself prove every dangerous surface is closed. strict specifically denies factory.create-from-code and other broad operations through its deny-by-default rule, but it allows specific framework operations ($source-code, snapshot.tree.oracle, $prompt, $response, $error, $cancelled) that may be acceptable in some hosted deployments and may need to be tightened in others. The launch hygiene tests verify the actual dangerous operations — dynamic code creation, source-code exposure, package UI loading, runtime tunnels, shell/eval, and Omega effects — are either denied or isolated to a non-control origin.

If a preset allows something too broad for hosted cloud, tighten the preset or add hosted-specific declarative rules. Do not invent a parallel mode system.

Trust surfaces and origin boundaries

Matrix subjects are not browser security boundaries. space.jessica.apps.foo and system.security are different on the bus, but if both are served from https://hivecast.ai the browser treats them as the same origin and any JavaScript at one URL can reach the other.

The doctrine, in one paragraph (from thesis Part 4.5):

Code that HiveCast did not author does not run inside the HiveCast control-plane origin. Untrusted-or-user-or-package-or-generated JavaScript runs either (a) inside a sandboxed iframe, preferably without allow-same-origin; if same-origin semantics are needed for the component's own assets or storage, the iframe must be served from a separate isolated origin and communicate through a capability bridge over postMessage, or (b) on a separate registrable domain (e.g. <feature>.hivecast.site) with cookie/storage isolation. Federation across Spaces means typed service contracts, not arbitrary UI code in a peer's trusted origin.

This rule constrains four feature classes:

  • Runtime tunnels — pages served by a user's runtime do not appear on the control-plane origin. Either iframe-embedded or on an isolated registrable domain.
  • Generated artifacts in Chat — agent-generated JS runs in iframe sandboxes; declarative artifact specs (rendered by trusted Chat code) are the default path. Custom-JS artifacts are the iframe path.
  • Package UIs — package-authored UI panels run iframe-sandboxed.
  • User-published Matrix sites — when this vertical ships (v3), the pages live on a separate registrable domain that has been submitted to the Public Suffix List so sibling subdomains cannot share cookies.

Status: target state — hivecast.site and PSL submission. A separate registrable domain (hivecast.site is the planned target) is needed as an origin boundary from matrix.hivecast.ai. PSL registration becomes load-bearing when HiveCast issues sibling user-content subdomains that must be isolated from each other. The PSL submission has not been done; do not claim it has. Today, none of the v0 / v0.5 features need either the domain or PSL because no custom-JS generated artifacts, runtime-served web tunnels, or user/package UI surfaces ship in those phases. The purchase + submission is cheap insurance against schedule risk for v3.

Singleton authority

Per MATRIX-AUTHORITY-MODEL.md:

Singleton authority mounts have one live owner per authority root. system.runtimes, system.registry, system.devices, system.auth, host.control. Two matrix up calls for the same singleton on one Host = silent claim collision.

Two writers to the same authority cause non-deterministic behavior. The rule is enforced by convention and discipline, not by automatic detection — every PR that touches a singleton must verify it does not introduce a second writer.

Anti-patterns to reject

These patterns appear regularly in design proposals. Reject them on sight.

Anti-pattern: "Just upload the OAuth refresh token to HiveCast so they can call APIs on the user's behalf"

This crosses the boundary from local Host to HiveCast cloud. Refresh tokens for Anthropic / Codex / OpenAI are issued via local-loopback OAuth and meant to stay on the Device. Sending them to HiveCast (a) has no benefit (the inference call goes Device->provider, not HiveCast->provider) and (b) creates massive blast radius if the cloud state is ever leaked. See USER-FLOWS-AND-AUTH-BOUNDARIES.md.

Anti-pattern: "Read <matrix-home>/credentials.json directly from this actor instead of going through Factotum"

This violates Rule 4. The lease/materialize discipline exists so the bus only ever carries lease IDs. If you need a third-party API from inside an actor, do credential.lease then hand the lease to the inference catalog (or another trusted system actor) which calls credential.materialize and gets HTTP headers ready to use.

Anti-pattern: "Trust payload.principalId because we already authenticated the caller upstream"

Violates Rule 5. Even when the upstream caller was authenticated, the payload is untrusted. Re-derive the principal from transport metadata (NATS auth user claims, HTTP session cookie, bearer-verified Host Link).

Anti-pattern: "Two matrix up for the same singleton on the same authority root"

Violates the singleton rule. Even briefly, while one is restarting and the other has not yet died. Use host.control's ownership model and ensure runtime IDs are unique per logical singleton.

Anti-pattern: "Inline the principal account seed into the pairing grant"

Violates the per-Device isolation rule from HIVECAST-DEVICE-ENROLLMENT-SPEC.md Correct Security Model: forbidden practices include "one raw principal account seed copied to all devices". Each Device gets a user JWT scoped to the principal's NATS account, not the account seed.

Anti-pattern: "Boot the hosted Host with the dev preset because it makes testing easier"

Violates the preset enforcement rule. Hosted production loads standard, strict, or lockdown. Local-dev convenience does not justify shipping a hosted Host where every op is allowed.

Anti-pattern: "Serve user-published or package-authored UI from the same origin as the control plane"

Violates the trust-surface doctrine. Any code HiveCast did not author runs sandboxed (iframe, preferably without allow-same-origin) or on a separate registrable domain. Federation between Spaces is typed service contracts on the bus, not foreign UI in the trusted origin.

Defense in depth

The design assumes individual layers can be compromised:

  • HiveCast cloud compromise: the cloud's principal credentials are recoverable, but the principal's per-provider OAuth tokens never travelled cloud-side. The blast radius does not span Devices.
  • Local Host compromise: the Device's NATS user JWT and heartbeat token are exposed, but they are scoped to one Device. Revocation cuts it off in seconds. Provider tokens stored by Factotum are exposed too, but only this Device's tokens — not the principal's everywhere-token.
  • Single-actor compromise: an actor that misbehaves still goes through the bus. Other actors can ignore its events; system-singleton actors are not callable from arbitrary mounts. The policy preset's deny rules add a second layer between actor mailbox and op execution.

See also

Source: PolicyPresets.ts (the four presets and the createPolicyEngine factory); USER-FLOWS-AND-AUTH-BOUNDARIES.md (boundary table); CLAUDE.md Rules 4, 5, 6; MATRIX-AUTHORITY-MODEL.md (singleton rule); thesis Part 4.5 (trust surfaces and origin boundaries).