Skip to content

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 on

Add 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

  • Transparentnpm install left-pad (wrapper picks it up; no syntax change)
  • Direct per-PM wrapperveln npm install left-pad, veln pip install requests, veln yarn add typescript, veln pnpm add zod, etc. One invocation, no PATH changes.
  • Explicit shorthandveln safe npm install left-pad or veln sandbox npm install left-pad
  • Preciseveln 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.
  • macOSsandbox-exec with 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 unwrapped
  • command 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.

← Documentation overview