Security Model

Steel enforces authorization on every function call. There are no implicit permissions, no trusted paths, and no shortcuts. Every execution is verified.

Zero-Trust Execution

In most plugin systems, once a plugin is loaded, it can call any import the host provides. Steel flips this: every call starts denied, and must earn permission through a policy evaluation.

This means even a compromised or malicious plugin cannot do more than the policy allows — and the policy can inspect the exact arguments, the target function, and the calling user's context.

Per-Call Authorization

Every function call passes through the policy engine before execution. Steel evaluates a Rego rule with full access to the call's metadata:

Input FieldWhat It Contains
object_idWhich plugin object is being called
facet_idWhich interface is being invoked
method_idWhich specific function is being called
method_nameThe human-readable function name
positionalThe positional arguments passed to the call
namedNamed arguments passed to the call

Policies can inspect any combination of these fields. A policy might allow a function only when called with specific arguments, or restrict it based on the calling user's role.

Default-Deny

If no policy rule exists for a call, it is denied. If the rule returns false, it is denied. If the rule errors, it is denied. Only an explicit true permits execution.

This means you must opt in to every capability. There is no background permission set, no "allow all" fallback, and no way for a plugin to escalate its own privileges.

Per-User Session Isolation

When a user authenticates, Steel creates an isolated execution environment for them. Each session gets its own:

Wasm Sandbox

Each user's Wasm instance has its own linear memory. One user cannot read or write another user's data, even within the same plugin.

Linker

Each user's linker only exposes the imports their role permits. Even if the sandbox were somehow escaped, the linker blocks unauthorized calls.

Policy Engine

Each session can have its own policy engine instance. Per-user policies can be loaded without affecting other users.

Defense in Depth

Steel provides two independent layers of enforcement:

  1. Policy engine — evaluates Rego rules on every call. This is the primary authorization layer.
  2. Linker — controls which imports are available. This is the structural enforcement layer.

These layers are independent. Even if one is bypassed, the other still enforces the security boundary. This is defense in depth: no single point of failure.

Example Policy

A Rego policy that only allows listing files when the caller has admin role and passes no more than 3 arguments:

package data.steel.auth.allow

default allow = false

allow {
    input.method_name == "execute"
    input.named.role == "admin"
    count(input.positional) <= 3
}

If this policy is not loaded, all calls are denied. If it is loaded, only calls matching all three conditions are permitted. Everything else is blocked.

Content-Addressed Integrity

Plugins are distributed as OCI artifacts with SHA-256 content addressing. Every plugin layer has a cryptographic digest. Steel verifies integrity on load — you always know exactly what code is running.