Skip to content

Guides

Policy profiles

Choose the right run profile, host-share mode, environment policy, and seccomp tier for a sandboxed workload.

Policy profiles are the first security decision for a sandbox run. Pick the least permissive profile that lets the workload do its job, then add filesystem, environment, network, and seccomp permissions deliberately.

For generated code, third-party code, model tool calls, and CI jobs, start with restrictive and relax only the specific boundary that blocks the workload.

mvmctl run supports four profile intents:

ProfileDefault useHost sharesEnvironment injection
restrictiveGenerated or untrusted code.Not allowed.Not allowed.
standardNormal local one-shot runs.Read-only only.Explicit --env KEY=VAL allowed.
devLocal iteration against a project tree.Read-only or writable.Explicit --env KEY=VAL allowed.
permissiveLast-resort local debugging.Broadest local mode.Explicit --env KEY=VAL allowed.

The default is standard. Use restrictive when the workload does not need host files or host-provided environment values:

Terminal window
mvmctl run --profile restrictive -- python task.py

Use standard when the workload needs explicit environment values or read-only input files:

Terminal window
mvmctl run --profile standard --mount ./fixtures:/fixtures:ro -- python task.py

Use dev for local development commands that need the broader development profile. Transient host-directory shares remain read-only:

Terminal window
mvmctl run --profile dev --mount .:/work:ro -- cargo test

Use permissive only when a local experiment needs the escape hatch. It requires an explicit acknowledgement so broad execution is visible:

Terminal window
MVM_ACK_PERMISSIVE_RUN=1 mvmctl run --profile permissive -- ./debug-script.sh

Transient host directory mounts are declared with:

Terminal window
mvmctl run --mount HOST:GUEST:ro -- command

Rules:

  • the mode must be ro;
  • restrictive rejects host directory shares;
  • standard accepts read-only host shares.

Prefer read-only shares for test inputs, source snapshots, fixtures, and model context. Use mvmctl machine cp or a managed volume when changes must persist.

Use explicit environment injection:

Terminal window
mvmctl run --env TASK_MODE=check -- python task.py

Rules:

  • restrictive rejects --env.
  • standard, dev, and permissive allow explicit --env KEY=VAL.
  • Do not pass secrets through argv or --env; use managed secret references where a secret is required.

Environment values are easy to leak through process listings, shell history, debug output, and crash reports. Treat them as configuration, not as a secret delivery path.

Use dry-run mode to check a run plan without resolving an image, booting a VM, executing the command, or writing a receipt:

Terminal window
mvmctl run --dry-run --json --profile restrictive -- python task.py

Dry-run output is redacted. It is useful in CI because policy failures can be caught before a workload starts.

Named VM launches expose a separate seccomp tier:

Terminal window
mvmctl machine run --flake ./my-app --name agent-sandbox -d --profile standard

Supported tiers are:

TierUse it when
essentialThe workload needs the smallest syscall surface the current guest can boot with.
minimalThe workload is simple and should run with a reduced syscall set.
standardDefault named-VM posture.
networkThe workload needs network-oriented syscalls beyond the standard profile.
unrestrictedLocal debugging only; avoid for untrusted code.

The selected tier is recorded in the signed admission profile for audit.

WorkloadStart withAdd only if needed
Model-generated codemvmctl run --profile restrictiveRead-only fixtures after review.
Code interpretermvmctl run --profile restrictiveA bounded work directory or receipt output.
CI validationmvmctl run --profile standardRead-only source share and explicit non-secret env.
Local developmentmvmctl run --profile devWritable project share.
Long-running local servicemvmctl machine run --profile standardExplicit ports, volumes, and readiness checks.

Security-first defaults should feel slightly strict. A denied --env or writable share is a useful signal that the run is crossing a boundary.

Profiles affect the run’s policy surface, so include evidence with automated runs:

Terminal window
mvmctl run --profile restrictive --receipt /tmp/run-receipt.json -- python task.py
mvmctl trust receipt verify /tmp/run-receipt.json

Use audit and receipts for portable proof and host-local investigation. Keep policy identifiers, run IDs, and audit IDs in higher-level logs instead of copying raw command payloads there.