Skip to main content

Workspace Composition Security And Trust Model

This document is the canonical spec for WCP-004: Write security and trust model v0.

It locks the v0 security posture for the workspace composition platform:

Modules declare contracts.
Host resolves runtime.
Composer composes structure.
Render runtime executes UI.
ClaudeWorkspace packages product defaults.
Modules are trusted React UI adapters, not state/runtime owners.

Linked Decisions

  • WCP-ADR-001: responsibility is split across host, composer, render runtime, product kit, and modules.
  • WCP-ADR-003: render handles are opaque and never executable UI.
  • WCP-ADR-004: React execution belongs to a scoped render runtime.
  • WCP-ADR-007: modules do not own persistent state.
  • WCP-ADR-008: grants are UI activation contracts.
  • WCP-ADR-009: v0 modules are build-time trusted React modules.
  • WCP-ADR-015: diagnostics are structured product inputs.
  • WCP-ADR-016: module CSS is scoped to assistant UI.

Scope

WCP-004 owns the security language for workspace composition v0:

  • v0 module trust assumptions
  • grant and permission vocabulary
  • host and backend enforcement responsibilities
  • secret handling rules
  • runtime summary and diagnostic redaction requirements
  • action model safety requirements
  • prohibited code loading paths
  • render runtime trust interpretation
  • CSS trust boundary requirements for modules
  • WCP-004 conformance gates

WCP-004 does not own package dependency rules, lifecycle script policy, workflow pinning, publish artifact policy, package export tables, namespace grammar, diagnostic code registry, composition merge semantics, React rendering behavior, backend authorization implementation, marketplace review, future iframe sandboxing implementation details, or external plugin signing.

Those remain owned by SECURITY.md, .docs/security/supply-chain.md, workspace-composition-module-authoring.md, workspace-composition-namespace-diagnostics-versioning.md, workspace-composition-kernel.md, and the future render runtime spec.

V0 Trust Model

v0 modules are trusted build-time npm packages that a developer installs, audits, locks, imports, and wires into the host app explicitly.

Trusted means the host has chosen to run the module code. It does not mean the module is sandboxed. A module runs with the normal frontend JavaScript authority of the host bundle once it is loaded.

The v0 model intentionally excludes:

  • end-user plugin marketplace installation
  • online dynamic module installation
  • runtime untrusted installs
  • remote ESM
  • URL-based dynamic imports
  • module federation remotes
  • iframe sandbox execution
  • micro-app plugin execution
  • automatic package discovery
  • import-time registration into global registries
  • local patching of built-in pages

Future external or untrusted plugin support requires reopening WCP-ADR-008 and WCP-ADR-009, because v0 has no code isolation boundary.

Enforcement Model

frontend grants are UI activation contracts. They tell module UI which capabilities the host has chosen to expose in the current session. They are not frontend authorization, backend authorization, or data protection.

backend and host policy enforce real authorization. host and backend enforce real authorization for every privileged operation, including reads, writes, exports, tool calls, mutations, cross-tenant access, and administrative actions.

The following are UX and composition controls, not security boundaries:

  • runtime.status
  • runtime.grants
  • runtime.missing
  • activeWhen
  • fallback surfaces
  • hidden routes or sidebar items
  • render handle matching
  • render runtime trust policy
  • disabled or read-only UI states

Backend APIs must derive authorization from authenticated server-side context. They must not trust a frontend grant, runtime status, route visibility, or render decision as proof of permission.

Host Responsibilities

The host owns security-sensitive decisions and state:

  • explicitly import trusted modules, render packs, and module CSS
  • resolve runtime from module contract, deployment capability, tenant policy, user permission, configuration state, backend health, and read/write mode
  • enforce tenant, user, resource, operation, rate limit, audit, and backend policy for every controller action
  • keep credentials, API keys, OAuth tokens, session cookies, refresh tokens, service credentials, signed URLs, private base URLs, raw headers, and credential-like configuration outside module descriptors and render props
  • expose intentional per-instance controllers instead of generic fetch, raw storage, auth clients, database clients, or backend clients
  • store persistent configuration, durable business data, health state, audit logs, synchronization state, and network transport outside modules
  • redact runtime summaries, action payloads, metadata, diagnostics, controller view models, and user-facing messages before composition
  • route rich diagnostics to development or administrator views and redacted summaries to ordinary production UI

The phrase host redacts means the host removes or summarizes sensitive values before they reach composeWorkspace, WorkspaceComposition, render handles, render props, diagnostics, fixtures, or user-facing fallback surfaces. The composer copies structure and diagnostics; it does not sanitize secrets.

Module Responsibilities

Modules are UI adapters for host capabilities. They declare contracts and adapt to the granted runtime, but they do not own security policy, persistent state, durable storage, network transport, or backend authorization.

Module code may keep transient component state such as tabs, expanded sections, draft input, hover state, popover state, loading spinners, and optimistic UI flags that are reconciled by host-owned controllers.

Module code must not own:

  • persistent configuration
  • credentials or secrets
  • cross-refresh state
  • tenant policy
  • user permission state
  • backend health state
  • audit logs
  • durable business data
  • storage synchronization
  • raw network clients
  • package-level runtime singletons

Modules must not read or write localStorage, sessionStorage, IndexedDB, cookies, service workers, credential stores, raw auth tokens, raw platform clients, or global registries as part of runtime behavior.

modules must not receive real secrets in factory options, descriptors, render handles, runtime summaries, metadata, labels, route params, diagnostics, CSS, fixtures, render props, or controller objects.

Grant And Action Vocabulary

Use these terms in public docs, API comments, and diagnostics:

  • UI activation grant
  • runtime grant
  • activation contract
  • granted capability UI
  • missing activation requirement

Avoid language that implies frontend security enforcement, such as secure grant, frontend authorization, permission enforcement by module, grant protects data, or authorized because granted.

Runtime actions are host-authored intents. The kind field must use the WCP-005 RuntimeAction.kind union: configure, authorize, retry, open, or custom. Product-specific intents such as connect, disconnect, or request access must use kind: 'custom' plus a stable, non-secret id, or WCP-005 must be reopened to add a new kind.

An action may identify a user-safe intent and a stable target, but it must not carry credentials, raw policy evidence, backend traces, or secret-bearing payloads.

Allowed runtime summary fields include:

  • instanceId
  • status
  • stable grant IDs
  • stable missing requirement IDs
  • user-safe action IDs, kinds, and labels
  • generic user-facing messages
  • non-secret status data needed for fallback UI

Host-provided resolved runtime input follows WCP-005 ResolvedModuleRuntime. It does not carry a separate readOnly boolean unless WCP-005 adds that field. The composed and rendered runtime summary may include the WCP-005 readOnly boolean derived from status === 'readOnly'; it is a UI state hint, not an independent authorization signal.

Forbidden runtime summary fields include:

  • secrets, tokens, cookies, credentials, or private keys
  • raw backend errors, stack traces, headers, requests, or responses
  • permission engine internals
  • tenant policy documents
  • raw storage keys
  • infrastructure identifiers that reveal private topology
  • signed URLs, including short-lived signed URLs, except redacted placeholders that cannot be used as credentials
  • PII beyond what the current user is already allowed to see in the host product

Diagnostic Redaction

Diagnostics exist to help hosts and module authors fix integration problems. They must be specific enough to identify the broken module instance and contribution, but they must not expose authority or sensitive data.

Safe diagnostic details:

  • packageId
  • packageVersion
  • instanceId
  • canonical contribution keys
  • route paths
  • renderer claims
  • render handle summaries
  • runtime status
  • schema versions
  • stable reason categories
  • redacted action IDs and action kinds
  • linked decision IDs

Unsafe diagnostic details:

  • API keys, tokens, cookies, secrets, credentials, auth headers, or private keys
  • raw request or response bodies
  • backend stack traces
  • full URLs with credential-like query parameters
  • signed URLs, including short-lived signed URLs, except redacted placeholders that cannot be used as credentials
  • policy rule bodies
  • user permission graph internals
  • controller objects or serialized component props
  • raw thrown error payloads
  • private tenant configuration

WCP-003 owns the diagnostic code registry. WCP-004 may require new security-related diagnostic categories, but concrete diagnostic codes must be added only in the WCP-003 registry.

Render Runtime Trust Boundary

WCP-006 owns exact React render runtime execution behavior. WCP-004 only constrains the security interpretation of that runtime.

For WCP-004 purposes, render runtime wiring is acceptable only when it:

  • uses render packs explicitly provided by the host
  • keeps render pack and controller access scoped to one instanceId
  • treats render runtime trust policy as admission, preload, fallback, and diagnostic policy, not sandboxing
  • fails closed to redacted fallback UI for unknown, blocked, failed, or unsupported handles
  • reports render failures through WCP-003 diagnostics after applying WCP-004 redaction rules
  • keeps lazy loading host-bundled and host-controlled
  • avoids global render registries, import-time auto-registration, package scanning, side-effect render pack loading, remote ESM, and runtime installation paths

Render-runtime fallback UI is host-owned placeholder or error UI for handle admission, lookup, or render failures. It is distinct from WCP-005 fallbackSurfaces, which are explicit module contributions materialized from resolved module runtime status. The composer never invents fallback UI.

blocked means rejected by the host render runtime trust policy before component execution; it does not mean denied by a frontend grant.

Prohibited Code Loading Paths

v0 forbids executable code paths that imply an untrusted plugin platform:

  • remote ESM loaded from http: or https:
  • dynamic imports derived from module descriptors, render handles, user input, or network data
  • runtime untrusted installs
  • online plugin marketplace install flow
  • module federation remote execution
  • script tag injection for module code
  • iframe, micro-app, or sandbox plugin execution
  • automatic package scanning or auto-discovery
  • import-time global registration
  • render pack loading as a side effect of importing a module descriptor

Static lazy imports inside trusted render packs are allowed when they are bundled by the host build and passed through an explicit scoped render runtime.

CSS Boundary

Trusted modules still share the host page, so CSS is part of the trust boundary.

Module CSS must be scoped below .aui-root, use --aui-* tokens where practical, and avoid global resets or selectors that target host application chrome.

Module CSS must not include unscoped html, body, :root, *, button, input, host selectors, remote imports, remote fonts, or automatic CSS injection from render pack side effects.

Conformance Checks

WCP-004 conformance is intentionally machine-checkable where possible:

The checks below are the v0 target policy and land with the code surface they protect. WCP-007 establishes the @maya/assistant-composition headless package boundary: no React/DOM/CSS/fetch/storage dependency and no package-local duplicate docs. WCP-008 extends that boundary with core type contracts, opaque render-handle shape checks, public .d.ts contract snapshots, and source checks against executable UI fields. WCP-009 adds namespace validation fixtures so conflict diagnostics stay deterministic without import-order or implicit override behavior. WCP-010 adds policy validation fixtures for explicit policy operations without adding a policy DSL, patch hooks, remote code loading, or runtime plugin installation. WCP-011 adds composeWorkspace() golden fixtures for runtime status gating, fallback materialization, route/renderer conflict diagnostics, and required render handle manifests without adding render execution. WCP-024 opens composition as the public headless contract package while keeping the same headless and no-runtime-code-loading constraints.

  • docs and public API comments describe grants as UI activation contracts, not authorization
  • module factories and controllers do not accept credentials, raw clients, storage adapters, or generic network clients
  • descriptors, render handles, runtime summaries, metadata, labels, actions, fixtures, and diagnostics do not contain secret-like keys or values
  • render packs are explicit, instance-scoped, and free of global registration
  • lazy imports are static, host-bundled, defined inside trusted render packs, and not derived from module descriptors, render handles, user input, network data, or other runtime data
  • source checks reject remote ESM, URL-based dynamic imports, script tag injection for module code, module federation remotes, iframe, micro-app, or sandbox plugin execution, automatic package scanning or discovery, import-time global registration, render pack loading as a side effect of importing a module descriptor, and runtime installation paths
  • module CSS is scoped below .aui-root and avoids global selectors, remote imports, and injection side effects
  • WCP-004 security assertions reuse the WCP-003 and WCP-005 runtime-status fixture inventory and add only leak checks for runtime summaries, actions, diagnostics, render props, and fallback surfaces
  • render runtime diagnostics use stable redacted reason categories and link to relevant decision IDs

Forbidden Drift

The v0 architecture must not slide into:

  • grants described as frontend authorization
  • the composer resolving permissions or redacting secrets
  • render runtime trust policy treated as sandboxing
  • modules owning persistent state
  • secrets in module props, runtime summaries, diagnostics, metadata, labels, route params, fixtures, or CSS
  • raw platform clients passed to module factories or controllers
  • remote code loading or runtime plugin installation
  • global registries or automatic discovery
  • local patching of built-in pages
  • unscoped module CSS

Reopen Conditions

Reopen WCP-004 only when one of these becomes true:

  • v0 cannot ship without a code loading path that is currently prohibited
  • a security finding proves that build-time trust is insufficient for the product requirement being implemented
  • a future marketplace or external plugin product requires a real isolation model
  • backend enforcement moves to a formally specified server-side plugin authorization system
  • CSS isolation tooling can prove a stronger boundary than .aui-root scoping

Any reopen must follow the decision-register reopen process in workspace-composition-decisions.md and additionally name the new enforcement boundary.

Duplicate Truth Boundary

WCP-004 owns security vocabulary and trust boundaries for workspace composition.

It links instead of copying:

  • SECURITY.md for repository vulnerability reporting and coordinated security fixes
  • .docs/security/supply-chain.md for package metadata, dependency protocols, lifecycle scripts, workflow policy, publish boundaries, and static supply-chain checks
  • workspace-composition-module-authoring.md for package exports, factories, render packs, CSS subentries, fixtures, and module authoring conformance
  • workspace-composition-namespace-diagnostics-versioning.md for namespace grammar, diagnostic code registry, schema version fields, and fixture inventory
  • workspace-composition-kernel.md for composition input, policy operations, runtime gating, result shape, and fallback materialization
  • package guides under .docs/packages for package consumption details