Sandbox & wrappers
The sandbox wraps every npm install / pip install in OS-native isolation. If a malicious package slips past the Gate, its postinstall script can’t write outside the project folder or reach the network. Shims are the friction-free way to apply the sandbox: install once, every package-manager binary routes through it automatically.
Enable it
One command wraps all fourteen package managers:
veln wrapper onAdd the shim directory (~/.veln/shims on Linux/macOS, %USERPROFILE%\.veln\shims on Windows) to the front of your PATH — the installer prints the exact one-liner for your shell. From then on, your existing commands route through the sandbox transparently.
Four ways to invoke
- Transparent —
npm install left-pad(wrapper picks it up; no syntax change) - Direct per-PM wrapper —
veln npm install left-pad,veln pip install requests,veln yarn add typescript,veln pnpm add zod, etc. One invocation, no PATH changes. - Explicit shorthand —
veln safe npm install left-padorveln sandbox npm install left-pad - Precise —
veln run -sandbox -with-gate -- npm install left-pad(full flag control)
Package managers covered
JavaScript: npm, npx, yarn, pnpm, bun.
Python: pip, pip3, uv, pipx.
Go / Rust / Ruby / .NET / JVM: go, cargo, bundle, dotnet, mvn, gradle.
poetry and gem aren't wrapped — they ignore the index/mirror env Veln sets, so they can't be routed through the gate. Gate them at the lockfile level with veln verify instead.
Run veln wrapper status to see which wrappers are installed and whether the directory is on your PATH. veln wrapper off reverts to the unwrapped package managers.
What the sandbox blocks
The mechanism differs per OS but the protection is consistent: writes outside the project folder (plus the package manager’s own cache) are denied, and outbound network is allowed only to the local Gate.
- Linux (kernel ≥ 5.13) — Landlock LSM. On kernel ≥ 6.7, also enforces a TCP allowlist that permits only the Gate port.
- macOS —
sandbox-execwith a default-deny SBPL profile (the same mechanism Chrome and Safari use to isolate their helper processes). - Windows — Job Object with kill-on-close + Restricted Token (DISABLE_MAX_PRIVILEGE) + Mandatory Integrity Level LOW.
When the sandbox denies an operation
A blocked operation surfaces in the package manager as a permission error. Veln detects the denial-shaped stderr and prints an advisory naming the exact path that was attempted, plus the interactive options:
- d — Deny and abort (default — recommended)
- a — Allow once and retry this run
- A — Allow forever for this project (persisted)
- G — Allow forever globally (persisted with
project = "*") - s — Show full captured stderr (debug)
- q — Quit without further prompts (propagates the original failure)
Persisted approvals are written to ~/.veln/sandbox-overrides.toml with the project path, requested path, operation type, and timestamp. The file is mode 0600.
Non-interactive behavior
Sandboxed sessions detect non-TTY contexts (scripts, automation) and fail closed — the install is refused rather than prompting. Override only when you trust the environment:
VELN_SANDBOX_NONINTERACTIVE=1— force non-interactive mode (also auto-detected)VELN_SANDBOX_NONINTERACTIVE_DEFAULT=allow-once— auto-allow each denial without prompting. Use only in a trusted internal environment.
On hosted runners with restricted kernel features (e.g., Ubuntu 24.04 with AppArmor restrictions on unprivileged user namespaces), the sandbox gracefully falls back to env-only mode instead of failing the install. Set VELN_SANDBOX_FORCE=1 to require OS-level sandboxing even there.
Disable or roll back
veln wrapper off— remove the wrapper scripts; package managers run unwrappedcommand npm install— bypass the shim alias for one invocation (bash/zsh)VELN_SANDBOX_PROFILE_VERSION=0— keep the shim but skip the OS-level sandbox (env-scrub only — useful for diagnosing breakage)
Observability
Set VELN_LOG_SANDBOX=1 to emit a JSON-line event per sandbox invocation (mechanism, project dir, gate, notes, non-interactive detection) on stderr. Useful in production to confirm the sandbox is firing and to spot misconfigured allowlists.
What the sandbox does not protect
Three things are out of scope and we say so up front:
- Runtime activation — once your app
require()s a package and runs in production, the sandbox doesn’t apply. Gate is your only defense for runtime payloads. - Build-output poisoning — a malicious bundler plugin can rewrite
dist/inside the project dir (which is writable by design). File-tree drift catches this at the next install. - Zero-day source vulnerabilities — we know what OSV knows. Pre-disclosure bugs slip through any CVE-based tool.