Skip to content

SDK security model

The SDKs are developer ergonomics on top of the same local microVM model as mvmctl. They should make secure workflows easier, but they do not move trust boundaries by themselves. The important question for every SDK workflow is: which code runs on the host, which code runs in the guest, and which artifacts cross the boundary.

BoundaryWhat runs thereSecurity rule
SDK client processPython, TypeScript, or Rust code that calls the SDK.Treat runtime SDK scripts as host code. Run only code you trust on developer machines and CI hosts.
Static declaration compilerSource parser and declaration extractor.Prefer this path for deployable workloads because it can read declarations without importing user modules.
Build boundaryBuilder VM and build pipeline.Linux builds, Nix evaluation, image assembly, and artifact verification belong in the builder boundary.
Guest microVMWorkload entrypoints, generated code, tools, and services.Guest code is isolated by the backend and policy; it is still allowed to create sensitive output.
Host control planeCLI admission, filesystem transfer, logs, receipts, policy, and backend control.Every crossing should be explicit, bounded, and auditable.
ModeHost executes user SDK scriptGuest executes workloadUse when
Static declarationNo module importNoYou need reviewable workload declarations and build inputs.
RecordYesNoYou trust the SDK script and want Workload IR or compile input.
PlanYesNoYou trust the SDK script and want admission review before launch.
LiveYesYesYou trust the SDK script and are ready for VM boot, file writes, logs, audit events, and cleanup.

Runtime scripts are not a sandbox for the SDK script itself. They are a way to record or drive sandbox operations. The microVM boundary applies once admitted work executes in the guest.

DataDirectionRule
Command argsHost to guestKeep secrets out of argv; they are easy to log and audit.
EnvironmentHost to guestPrefer secret references or managed injection over plaintext values.
File writesHost to guestUse narrow paths; reject traversal and broad host-directory mirroring.
File readsGuest to hostTreat returned bytes as untrusted and possibly sensitive.
LogsGuest/control plane to hostRedact credentials and bound log size before attaching logs to automation.
PortsGuest to host/networkRequire explicit bindings and policy for every exposed service.
Receipts and audit IDsRuntime to hostPreserve them with job records so actions can be traced later.
Snapshots and cold stateGuest/backend to host storageTreat as sensitive state; memory and files can contain credentials and user data.

SDK examples should follow these defaults:

  • prefer static declarations for workloads that come from users, agents, or review queues;
  • prefer Nix flake targets for reproducible, auditable images;
  • pin OCI inputs by digest when using compatibility images in production;
  • deny network access unless a workload declares the exact egress it needs;
  • use secret references rather than string literals in source code;
  • set explicit TTL, cleanup, or detach policy for every sandbox;
  • preserve receipt and audit identifiers in result objects;
  • require explicit snapshot retention and deletion choices;
  • surface backend capability errors instead of silently falling back to a less secure lifecycle path.

SDK errors should distinguish:

  • policy denial;
  • build or admission failure;
  • guest command failure;
  • timeout;
  • transport failure;
  • cleanup failure;
  • snapshot or restore mismatch;
  • unsupported backend capability.

Do not convert these into a single generic exception in application code. The caller needs different recovery behavior for policy denial, guest failure, transport failure, and cleanup failure.

from mvm import NetworkPolicy, Sandbox, SecretRef
with Sandbox.create(
image="nix:./flake#agent-runtime",
network=NetworkPolicy.deny_by_default().allow_https("api.openai.com"),
secrets={"OPENAI_API_KEY": SecretRef("openai-api-key")},
ttl_seconds=1800,
) as sandbox:
result = sandbox.commands.run(["python", "/work/tool.py"], timeout_seconds=30)
print(result.stdout)

This is the target SDK shape. Check Lifecycle matrix before treating a helper as shipped in a particular language.