Sandbox

The default execution posture, with a bin allow-list, a cwd jail and no ambient credentials, and why native-local is a trust decision you opt into.

On this page

Packs wrap real binaries, so a runtime sandboxes them unless someone opts out on purpose. Leave the sandbox on everywhere except a personal machine whose owner has chosen to trust the host PATH.

ModeWhenBehaviour
sandbox (default)Cloud, CI, demos, most harnessesAllow-listed bins only; cwd jail; no host secret inheritance beyond Binding mint
native-localExplicit desktop trust on a personal machineHost PATH bins under user consent

What the sandbox enforces#

Bin allow-list#

A pack may spawn only binaries the runtime allows, and an unknown bin fails closed. There is no fallback to a PATH lookup, which would let a pack smuggle in an executable the operator never approved.

JSON
{ "ok": false, "error": "sandbox: bin \"transit\" not allowlisted" }

The reference runtime starts the allow-list with hcpx and hcp, or with the allowBins you pass instead, and adds the wrap.bin of every pack it loaded.

Working-directory jail#

Execution stays in a known cwd, the pack directory in the reference runtime, so a wrap cannot wander the filesystem through relative paths. Land local binds to this directory.

No ambient credentials#

Binding mint never falls back to environment tokens, so an installed pack cannot inherit whatever is exported in the shell. Env-flag mocks (PACK_MOCK=1) are ignored, and a mock is mode: mock in the envelope.

Marked environment#

The child sees HCP_SANDBOX=sandbox (or native-local), so a wrapped bin can refuse dangerous paths when sandboxed. The runtime also merges the manifest's agent_env into the child environment and special-cases nothing else per bin.

Configuring the reference runtime#

TypeScript
const hcp = await Hcp.create({
  packDirs,
  sandbox: true,               // default
  allowBins: ['transit', '/opt/tools/ledger'],
})

allowBins accepts bare names or absolute paths, and a bare name matches a bin whose path ends in /<name>.

Native-local#

TypeScript
const hcp = await Hcp.create({ packDirs, sandbox: false, nativeLocal: true })

Both flags are required, and sandbox: false alone still yields sandbox mode. Native-local is a trust decision about the machine, meant for a personal desktop where the user has consented to host PATH execution, so never turn it on to make a demo work.

Hardening beyond the reference#

A process allow-list plus a cwd jail is the minimum. Containers, microVMs, seccomp profiles and network egress policy per Binding are adopter upgrades that slot in under the same profile, and packs stay the same because isolation lives in the runtime.

LayerReferenceUpgrade
ProcessAllow-listContainer / microVM
Filesystemcwd jailRead-only root, mounted pack dir
NetworkInheritedEgress per Binding family
SecretsMint onlyShort-lived, scoped, injected as files