Sandbox any program to only what you allow

Run any program so it changes only the folders you give it, reaches only what you allow, and never reads Link's settings. Every Link agent runs in it, and so can anything else.

lnk sandbox ready                           # whether the sandbox can run here, and on Linux what it needs
# a shell that can change only this folder
lnk sandbox run --write . -- bash
# the internet, but nothing on this machine or its network
lnk sandbox run --internet-host '*' -- curl -sI https://example.com
# a sandbox written down, below: only what its file opens
lnk sandbox run --spec app.toml -- node app.js
lnk sandbox check --write .                 # try from inside what it should not allow
lnk sandbox log                             # every call on the proxies of the sandboxes

What it needs

You need a Mac, whose Seatbelt is built in, or Linux with bubblewrap. The sandbox plugin comes with every harness, and lnk plugin add sandbox installs it alone. It's free and needs no account.

Run a program

How to run a program in the sandbox, with only the folders you give it, or with all of it written down in a file.

Run a program in the sandbox

The program reads the system's programs and libraries, and nothing else unless you open it. It has no network. Its environment is cleared, so no tokens or SSH_AUTH_SOCK from your shell reach it. run exits with the command's status.

lnk sandbox run --write ~/Projects/site -- npm run build
lnk sandbox run --read ~/Documents/reports --write . -- python3 summarize.py
lnk sandbox run --read '~' --port 5432 -- ./tool

Its arguments

Arguments after -- reach the program unchanged, including option names also used by the sandbox's internal launchers.

--write and --read

--write <dir> is a folder it may read and write, and --read <dir> one it may only read. Both repeat, and --read '~' reads your whole home folder except Link's settings. --port <port> lets it connect to a port on this machine's loopback.

--hide

--hide <dir> closes a folder to it even then, except for the --write and --read folders inside it. Agents' folders in ~/Link/Agents, and what agents that left kept in ~/Link/History, are always hidden this way.

Every flag is a key

Every flag is a key of a spec, the file the next section writes. lnk sandbox permissions lists each section and its flags, and lnk sandbox run --help describes them.

Describe a sandbox in a file

A spec is a TOML file whose sections are the sandbox's only grants: [files], [internet], [lan], [localhost], [tools], [browser] and [commands]. A section left out stays closed, so a spec with no sections reads none of your files, reaches no network and runs no program. The spec lists every key and what it takes.

lnk sandbox spec --write ~/code/app --internet-host '*' --command node > app.toml   # a spec to start from
# shows what a new spec opens, and asks
lnk sandbox run --spec app.toml -- node app.js
# without asking
lnk sandbox run --spec app.toml --yes -- node app.js
lnk sandbox check --spec app.toml                    # try from inside what it should not allow
lnk sandbox spec --spec app.toml                     # the spec, paths absolute
name = "app"
version = 1

[files]
write = ["~/code/app"]

[internet]
hosts = ["registry.npmjs.org", "api.openai.com"]

[commands]
allow = ["sh", "node", "npm"]

Asked first

A spec can come from anyone, so one you haven't run here, or one that opens something different now, shows what it opens and asks first. --yes answers for you. A flag beside --spec replaces that key of the file's, except --hide, which adds to it.

What it can't open

A spec can't open Link's settings, agents' folders, or anything that would let a program reach outside the sandbox (each).

Let it commit

At the top of each folder it writes, a project's dot files that run outside the sandbox, such as .git, .envrc, .vscode and .idea, are read only (the full list). So git status, diff and log work, and a commit, git config or a new hook needs --write-dot-files to name the folder, or [files] write_dot_files in a spec.

# reads the repository, cannot change it
lnk sandbox run --write . -- git status
# commits
lnk sandbox run --write . --write-dot-files . -- git commit -qam fix

Why they're read only

What's written there would run as you, outside the sandbox, the next time you run git, cd into the folder or open it in your editor.

Only the top

Only the top of each folder is kept read only, so a repository the program clones or makes in a folder inside is its own to write. Give it the project's folder, not the one holding all your projects.

Choose what it can reach

The programs it runs, the hosts, machines and models it reaches, the tools it calls and the pages it opens, each a flag of lnk sandbox run and a key of a spec: Choose What It Can Reach.

Answer what a sandbox asks

A call that asks you first, such as a tool's or a page to open, shows a dialog on this computer's screen, asks on the terminal the sandbox started from, with a four-letter code to type back, and for an agent's sandbox asks on your chats. Two minutes without an answer is no, ten for an agent's, and the first answer counts; the sandbox's settings and the agent's spec change the wait (Tools and Asking).

lnk sandbox asks                  # what is waiting
lnk sandbox answer k7m2pq yes     # allow that call, once
lnk sandbox answer k7m2pq no

asks lists each question in a table of its ID, the QUESTION and the time it has LEFT, after which it counts as no.

With no one to ask

With neither, such as an agent in the background on a box, a tool's call is refused at once, naming the lnk sandbox tool add <tool> --allow <call> that lets it through, and with no desktop a page to open is refused at once, there being no browser to open it in.

Check it, and watch it

Try the sandbox from inside, see every call on its wire, and what each sandbox sent.

Check the sandbox

check plants bait, such as secrets in your home folder, in Link's settings and in each --hide folder, and a server on another port. It tries to reach each from inside, then removes it, and reports each try.

lnk sandbox check                           # the bare sandbox
lnk sandbox check --write . --internet-host '*'   # as a program would run
lnk sandbox check --spec app.toml           # as a spec would run, an unlisted program too
lnk agent harness check --harness link      # the sandbox of your agent, as Link Harness has it

What it reports

blocked when the sandbox stopped it, allowed when a folder or permission you gave lets it through, failed when it was allowed but didn't work here, missed when it should have been allowed and wasn't, and open for a known gap.

leaked

Something nothing allows got through. It exits 1, and please report it (Security).

See every call on the wire

Each line is a call on a sandbox's proxy: when (UTC), which sandbox, the verb, where to, and what happened. The log never holds a request's path, headers or body.

lnk sandbox log                              # the latest 40
lnk sandbox log --lines 200 --sandbox main-link
lnk sandbox log --refused                    # only what was refused
lnk sandbox log --json                       # one JSON object per line

A sandbox's name and a verb

A sandbox is named <agent>-<harness>, a box user's name or run-<pid>. The verb says what kind of call it was, such as connect for HTTPS, tcp for another port or model for a hosted model, and Security lists them all.

What happened

allowed, then ended with the bytes each way, or refused, or failed when it was allowed but nothing answered; an upstream socket refused for being another user's says so after failed.

See what each sandbox sent

This is what each running sandbox's proxy has carried since it started, up from the sandbox and down to it. lnk measure reads it as an agent's network; a hosted model's tokens are counted by its route, read from the usage each answer gives as it passes, and lnk measure reads them as the agent's.

lnk sandbox traffic                          # each running proxy: bytes up and down
lnk sandbox traffic --json

Stop or pause a sandbox

Closing a wire refuses every new call and ends open ones within a second. stop works however an agent behaves, and the log stays.

lnk sandbox stop                       # close every wire and stop every agent here
lnk sandbox stop --off                 # open the wires again, but agents stay stopped until lnk agent start
lnk sandbox pause main-link        # close the wire of one sandbox, while its program keeps running
lnk sandbox resume main-link
lnk sandbox paused                     # which wires are closed, and why

Without a wire

A sandbox without a wire, such as an agent with --network-mode host, stops only when its program does. An agent with no sandbox keeps its wire, but it closes only the calls the agent sends its proxy, which no wall keeps it to.

A wire that pauses itself

A proxy also pauses its own wire when its calls look like no normal work, and notifies you. That means 30 calls refused within a minute, 20 different targets refused within 10 minutes, or any call to a cloud's metadata service.

Seeing it

lnk sandbox paused and lnk sandbox log show which wires are paused and why. lnk agent status shows its own, for a box where no notification shows.

Let someone SSH into a sandbox

On a box, a person gets a Linux user of their own, whose every SSH session is in their sandbox: A box's users. What their key runs is lnk sandbox enter, which any key's forced command can run.

restrict,pty,command="/usr/local/lib/lnk/lnk-sandbox sandbox enter --spec /etc/lnk/users/alice/alice.toml --folder /home/alice" ssh-ed25519 AAAA...

A session

A shell, a command, scp or sftp (the session's SSH_ORIGINAL_COMMAND) all run in the sandbox the spec makes, named for its file, with the folder the one place it writes. Its [commands] must let /bin/bash run, which a session is.

--check

lnk sandbox enter --check says what the sandbox opens, a line each, and runs nothing; a command after -- runs in place of the session's.

Make the sandbox work on this machine

On Ubuntu 23.10 and newer, ready also offers to add an AppArmor profile with sudo, or prints the two commands. lnk agent start, run and check run ready first, once a boot on Linux, and on a Mac there's nothing to do.

# Linux
sudo apt install bubblewrap
lnk sandbox ready

Where things live

Link keeps the sandbox's files in your settings folder, where no sandbox reaches them: ~/.lnk/sandbox/ holds your tools, the wire's log and waiting questions, and ~/.lnk/specs/sandbox.toml lists the specs run here, so a new one asks first (how).

More about it

What the sandbox guarantees, and its known gaps, are in Security. Why it works this way is in Decisions. How a plugin uses it is in Plugin Contracts. What to do when it fails is on Troubleshooting.

Docs

  • Features: Every feature of the sandbox, one row each, grouped by what it opens or closes
  • Choose What It Can Reach: The programs a sandboxed program runs, the hosts, machines and models it reaches, the tools it calls and the pages it opens, each a flag of lnk sandbox run and a key of a spec (Sandbox)
  • Tools and Asking: The tools that run outside every sandbox, and how the sandbox asks you before one's call or a page goes through (Security)
  • Configuration: The files lnk sandbox keeps, and what each one holds
  • Security: What every sandbox guarantees, what can cross it, and how a spec is checked
  • Gaps and Limits: What the sandbox leaves open, what check reports as open, and where it can't run (Security)
  • Decisions: Why the sandbox works the way it does
  • Troubleshooting: What to do when the sandbox can't start here, a program in it can't write, run or reach what it needs, or your agent's grants don't hold (Sandbox, Permissions)