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.
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.
| Mode | When | Behaviour |
|---|---|---|
sandbox (default) | Cloud, CI, demos, most harnesses | Allow-listed bins only; cwd jail; no host secret inheritance beyond Binding mint |
native-local | Explicit desktop trust on a personal machine | Host 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.
{ "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#
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#
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.
| Layer | Reference | Upgrade |
|---|---|---|
| Process | Allow-list | Container / microVM |
| Filesystem | cwd jail | Read-only root, mounted pack dir |
| Network | Inherited | Egress per Binding family |
| Secrets | Mint only | Short-lived, scoped, injected as files |