The Alpha
The Alpha is the working prototype of the VPN Works engine: one Go program called vpnw, its tests, a few tools and a demo. On Linux it runs a program in a sealed sandbox whose only way out is vpnw. Each connection is decided by a policy, sent down the path you chose and recorded.
Everything so far ran on one Linux machine, a virtual machine with two CPUs. The demo’s agent, servers, office and attacker are stand-ins in a private network namespace. The engine also compiles for arm64 Linux and for macOS, but neither build has run yet. On macOS it is meant to route and trace programs that honor proxy settings; it can’t seal them. No real coding agent has run under vpnw so far. That is the job of the Beta.
Where it stands. A working engine with a sealed sandbox, tested hard on one Linux machine. Next it has to prove itself with real agents, on more systems.
- 3.6 MB: the whole engine, one Linux binary with no third-party code (1.5 MB compressed).
- 14 of 14: ways out of the sealed sandbox tried, and all blocked. Two IPv6 rows couldn’t run: the test machine has no IPv6.
- 24 of 24: deliberately planted bugs caught by the tests.
- About 1 ms: added to each new connection in a sealed run.
On this page: In brief · How it is built · The sandbox · Decisions and paths · Record and learn · Tests · Speed and size · Features and limits · The demo · Where it stands
The Alpha in Brief
| Area | Status | Key figures |
|---|---|---|
| Engine | Complete for the Alpha scope | One Go program: 5,459 lines in 24 files, standard library only |
| Sandbox | Working on Linux | A network namespace with loopback only, and a seccomp filter. No root needed |
| Paths | Direct and proxy | SOCKS5 and HTTP proxies, with names resolved locally or at the exit. WireGuard is Beta work |
| Tests | Extensive, on one machine | 57 test functions, 97 with subtests; 14 of 14 ways out blocked; 24 of 24 planted bugs caught; 6.95 million fuzzed inputs; 77.4% of statements covered |
| Speed | Measured on one machine | About 9 ms more to start, about 1 ms more per new connection, 789 MB/s through the sandbox |
| Platforms | Linux x86-64, run and tested | arm64 Linux and macOS compile, not run yet. On macOS, route and trace only by design |
| Demo | Six recorded runs | A stand-in agent, servers, office and attacker in a private network namespace |
| Readiness | TRL 4 | “Technology validated in lab”, on the European Commission’s scale |
How It Is Built
- One program. vpnw is one static binary. It is also its own sandbox helper: it starts a copy of itself inside the new namespaces.
- Go, standard library only. Go 1.24, with no third-party modules at all. That includes the configuration reader: the standard library has no TOML, so vpnw carries a small strict reader of its own.
- No daemon, no account. vpnw runs when you run it and stops when the program stops. The only thing it leaves behind is the last trace, kept for learn.
- Strict configuration. Every file carries a version number. An unknown key is an error, reported with its line number, never silently ignored.
- One core for every command. run, trace and guard are the same code with different options: one process runner, one path, one policy and one event bus. That is what lets them combine in a single command.
- Fail closed. When vpnw can’t give what was asked for (a sandbox, a working path, a policy that loads), it stops before the program starts, with its own exit code.
- License. The engine is not public yet. The license will be chosen before the first public release. The plan is a proprietary engine, with an open-source branch under consideration. Until then the prototype is marked “all rights reserved”, and the live demo is the way to see it run.
| Part | Lines | What it does |
|---|---|---|
| cmd/vpnw | 540 | The command line: run, trace, guard, learn, doctor and version |
| process | 907 | The sandbox: namespaces, the helper, capabilities, the seccomp filter, the proxy variables |
| broker | 817 | The proxy front end outside the sandbox: HTTP CONNECT, plain HTTP and SOCKS5. It decides, connects, relays and counts |
| policy | 606 | Rules, the five-step decision, deny_private and its ranges |
| path | 405 | Direct and proxy paths, and the health check before a program starts |
| config | 979 | The strict TOML reader and the checks on every file |
| events | 509 | The event model, text and JSON Lines output, and reading traces back |
| learn | 332 | A draft policy from a trace |
| plan | 130 | What the broker would do with a request, shared with the browser demo |
| wasm | 225 | The browser build’s interface to the engine |
| version | 9 | The version string |
Lines of Go, tests not counted. The tests add 2,439 lines.
The Sealed Sandbox

How a Sealed Run Starts
- vpnw checks the path. If a proxy was chosen and doesn’t answer, it stops with exit code 123 before anything starts.
- It starts the helper in a new user namespace and a new network namespace. The user namespace is what lets an ordinary user do this without root.
- The helper brings up loopback and checks that loopback is the only interface. If anything else is there, it refuses to go on (exit code 122).
- It listens on 127.0.0.1:3128 for HTTP proxy requests and on 127.0.0.1:1080 for SOCKS5, on the sandbox’s own loopback. Each connection to them is carried over a Unix socket to vpnw’s broker outside.
- It clears the capabilities the program could inherit and, unless
--allow-unix-socketswas given, sets no_new_privs and installs the seccomp filter. All of this happens on the thread that will start the program. - It starts the program with HTTP_PROXY, HTTPS_PROXY and ALL_PROXY pointing at the two ports, NO_PROXY removed, and NODE_USE_ENV_PROXY set so that Node.js honors the others.
Two Walls
The network namespace. The sandbox has no interface except loopback and no route anywhere. A direct connection, a UDP packet, a raw socket or a DNS query from the program or any of its children has nothing to travel on.
The seccomp filter. Unix sockets live in the file system, not in a network namespace, so the first wall alone would leave local services within reach. The filter makes socket(AF_UNIX, ...) fail with “operation not permitted”. It also refuses io_uring, which can create sockets without calling socket(), and any system call made through another architecture’s numbering, so there is no second system call table to go through. socketpair still works, so programs can talk to their own children. Like every seccomp filter, it passes to the program’s children and can’t be removed. --allow-unix-sockets leaves it out for programs that need a local socket, and the run’s record says so.
What It Needs From the Machine
Sealed runs need a Linux kernel that allows unprivileged user namespaces. Most distributions do. Ubuntu 23.10 and later restrict them through AppArmor, and vpnw doctor reports that; the Beta ships the AppArmor profile that lifts it for vpnw. vpnw is meant to run as an ordinary user. Run as root, the program in the sandbox keeps root’s power over the machine’s files, which the Alpha doesn’t limit.
Decisions and Paths

The Order of a Decision
Every request goes through the same five steps, and the first step that decides wins: deny rules on the name, deny rules on every address the name resolved to, deny_private on every address, allow rules, and finally the default. The default is set in the policy. When a policy has an allow list and no default, the default is deny.
A denied name is never looked up, and under a default of deny neither is a name that no allow rule matches, because a DNS query can carry data out too. Before a decision, vpnw looks a name up only when an address could change the answer: when the name is allowed and deny_private or an address deny rule still has to be checked, or when the default is allow. Once a name is allowed, vpnw looks it up to connect, if it hasn’t already, unless the path resolves names at its exit. When a name resolves to several addresses, every one of them has to pass.
Rules
| Rule | Matches | Doesn’t match |
|---|---|---|
github.com |
github.com | api.github.com, evilgithub.com |
*.github.com |
api.github.com, a.b.github.com | github.com, badgithub.com |
140.82.112.6 |
That address typed as a number. As a deny rule, also any name that resolves to it, on paths that resolve names locally | As an allow rule, a name that happens to resolve to it |
10.0.0.0/8 |
Any address in the range typed as a number. As a deny rule, also names that resolve into it, on paths that resolve names locally | As an allow rule, names |
api.github.com:443 |
That name on port 443 only | Other ports |
deny_private refuses loopback, the private ranges, carrier-grade NAT, the link-local range where cloud metadata services live, and the other special-purpose ranges of IPv4 and IPv6: 25 ranges in all. IPv4 addresses carried inside IPv6 (IPv4-mapped, NAT64 and 6to4) are judged by the IPv4 address they carry. A host name made only of digits, such as 2130706433, is refused.
Paths
| Path | How it connects | Where names are resolved |
|---|---|---|
| Direct | From this machine | On this machine |
| SOCKS5 proxy | Through the proxy | On the command line as in curl: on this machine with socks5://, at the exit with socks5h://. In a file, at the exit unless dns = "local" |
| HTTP proxy | Through the proxy, with HTTP CONNECT | At the exit, unless dns = "local" |
Proxy passwords are supported and never shown in messages or events. On a path that resolves names at its exit, vpnw can’t see where a name points, so it refuses a policy that would need to: deny_private with a default of allow is rejected on such a path, before the program starts. A path is checked before the program starts, and vpnw never falls back to a direct connection.
The Record and Learn
Every run is recorded as events, schema version 1. There are twelve event types: run.start, process.start, dns.query, dns.result, connection.attempt, policy.allow, policy.deny, connection.open, connection.close, connection.error, process.exit and run.end. They are printed as text while the program runs, or as JSON Lines with --json, and --out FILE writes them to a file as well. The last trace is kept for learn unless --no-save is given.
Events keep names, addresses, ports, byte counts, times and decisions. They never keep the data sent, URL paths, headers, environment variables or proxy passwords. Every connection ends as opened, denied or failed, and the summary at the end of a run adds up.
learn reads a trace, the last one or any file, and writes a draft policy: default deny, deny_private on, and one allow rule per destination the program reached, with a comment saying how often and on which ports. It lists destinations that were tried but never reached, so a person can decide whether they need another path, and it marks what a reviewer should look at: denied destinations, raw addresses, and connections that sent much more than they received. --ports writes host-and-port rules, and --wildcards folds three or more subdomains of one domain into a wildcard. The draft starts with “Read it before you use it”, because learn allows what the program did, leaks included.
Tests
Every test runs on Linux against the real engine. The integration tests start the real binary and seal real programs. All suites pass.
| Suite | What it checks | Result |
|---|---|---|
| Unit tests | Rules and decisions, deny_private ranges, configuration errors with line numbers, SOCKS5 and HTTP CONNECT paths, the broker, events, learn, the proxy variables, and the seccomp filter, run through a small interpreter | 47 test functions, 24 subtests; all passed |
| Integration tests | The real binary, sealed: routing through the broker, guard’s denial and exit code, the program’s own exit code, standard input, a dead path refused before start, socketpair, --allow-unix-sockets, and a program run as an ordinary user holding no capabilities |
10 test functions, the bypass matrix among them; all passed |
| Bypass matrix | 16 ways out of the sandbox. Each row lists the errors it accepts and fails on anything else; most rows aimed at this machine also run a control outside the sandbox | 14 blocked, 2 skipped: this machine has no IPv6 |
| Race detector | The whole suite under Go’s race detector | Clean |
| Fuzzing | Four targets, one minute each: the configuration reader, the rule parser, policy decisions and the broker’s front end | 6.95 million inputs, no crash |
| Plan against broker | The request plan the browser demo uses, compared with the running broker | 119 cases, all the same |
| Browser engine | The TinyGo build in the demo, compared with the standard Go build | 471 calls, identical answers |
| Planted bugs | 24 deliberate bugs in the policy, the broker, the paths, the sandbox, the record and learn, one at a time | 24 of 24 caught |
| Coverage | Unit and integration tests together | 77.4% of statements |
Coverage by part: policy 93.2%, learn 94.8%, plan 88.2%, broker 84.4%, config 79.8%, path 72.2%, events 70.8%, process 64.4%, the command line 59.8%.
The Bypass Matrix
A sealed program tries each way out below. Each row lists the errors it accepts, usually one, and fails on anything else, success included. Rows aimed at a listener on this machine also check that nothing arrived, and most of them run the same attempt once outside the sandbox as a control, to show the attempt itself works.
| Way out | Inside the sandbox | Outside (control) | Result |
|---|---|---|---|
| IPv4 TCP to this machine’s loopback (127.0.0.1) | Nothing listening in the sandbox | Reached | Blocked |
| IPv4 TCP to this machine’s own address | No route | Reached | Blocked |
| IPv4 TCP to a public address (1.1.1.1:443) | No route | Reached | Blocked |
| IPv4 TCP to a private address (10.0.0.1:80) | No route | Not needed | Blocked |
| IPv4 TCP to cloud metadata (169.254.169.254:80) | No route | Not needed | Blocked |
| UDP to this machine’s own address | No route | Reached | Blocked |
| UDP to a public DNS resolver (8.8.8.8:53) | No route | Not needed | Blocked |
| DNS lookup through the system resolver | Name lookup failed | Not needed | Blocked |
| Raw IP socket (ICMP echo to 1.1.1.1) | No route | Not needed | Blocked |
| A child process connecting on its own | No route | Not needed | Blocked |
| Abstract Unix socket | Not permitted | Reached | Blocked |
| Unix socket in the file system, like the Docker socket | Not permitted | Reached | Blocked |
| io_uring, which can create sockets without socket() | Not permitted | Reached | Blocked |
| A system call through the x32 table | Not permitted | Not needed | Blocked |
| IPv6 TCP to loopback (::1) | Not run | Not run | Skipped: no IPv6 on this machine |
| IPv6 TCP to a public address | Not run | Not run | Skipped: no IPv6 on this machine |
Planted Bugs
To check the tests themselves, 24 bugs were put into the engine on purpose, one at a time, and the test suite was run against each. A bug counts as caught only if a test fails.
*.example.comalso matches badexample.com- An exact rule for github.com also matches evilgithub.com
- deny_private forgets the link-local range, where cloud metadata lives
- deny_private is not checked on the addresses a name resolved to
- With a default of allow, names are no longer looked up for deny_private
- Only the first address of a name is checked
- A private IPv4 address wrapped in NAT64 form is let through
- Numeric host names such as 2130706433 are accepted as names
- A path that resolves names at its exit quietly weakens deny_private
- The broker connects even when the policy says deny
- Proxy credentials are forwarded to the destination server
- The SOCKS5 port stops asking for the per-run token
- A configuration file of an unknown version is accepted
- The sandbox starts even with a network interface other than loopback
- The program keeps a capability the sandbox helper needed
- The Unix-socket filter is never installed
- The filter checks the wrong address family and lets Unix sockets through
- 32-bit system calls walk around the filter
- A NO_PROXY setting survives and tells programs to go around vpnw
- A proxy password appears in events and messages
- learn allows destinations that were denied during the trace
- The run summary stops counting connections that opened
- guard exits with 0 after a denial, so scripts and CI never notice
- A dead proxy is not caught before the program starts
All 24 were caught.
Defects Found and Fixed
Building and testing the Alpha turned up these defects. All are fixed, and each is covered by a test:
| Defect | Found by | Effect before the fix | |
|---|---|---|---|
| 1 | A sealed program could still connect to a Unix socket in the file system, such as Docker’s | The bypass matrix, which listed it as a known gap until it was closed | A local service could have made connections on the program’s behalf |
| 2 | In builds with cgo, the helper couldn’t clear the capabilities of an ordinary user’s program | The test that runs a program as an ordinary user | vpnw stopped with exit code 124 instead of running the program |
| 3 | One jump in the new seccomp filter pointed at the wrong instruction | Code review, before the filter ever ran. It is now run through an interpreter in the tests | The filter would have refused an unrelated system call, write on x86-64, and broken every program |
| 4 | The run summary counted failed connections twice | Review; a test now checks that opened, denied and failed add up | Wrong totals in the record |
| 5 | With two files on the command line, the policy took the other file’s name | Building the demo | A misleading policy name in the record |
| 6 | Some bypass rows passed for the wrong reason, such as a missing tool or no IPv6 | Review of the matrix. Each row now lists the errors it accepts, with controls and explicit skips | Rows that proved nothing counted as blocked |
What the Tests Do Not Cover Yet
- Real agents. Only a stand-in agent has run under vpnw.
- Other machines. One kernel (Linux 6.18), one distribution, x86-64 only. The arm64 build compiles but hasn’t run, and the AppArmor restriction on Ubuntu hasn’t been tried.
- IPv6. The test machine has no IPv6, so the two IPv6 rows were skipped, not passed.
- macOS. The build compiles but hasn’t run on a Mac. By design it can only route and trace there.
- Files. vpnw limits the network only. A sealed program can read what its user can read, and it can write files that another program may run later, outside the sandbox.
- Silent walls. A program that tries to go around vpnw fails, but the attempt doesn’t show in the record.
- Time. Fuzzing ran for one minute per target, and the longest run under vpnw lasted seconds.
- Independent review. Every test was written by the people who wrote the code.
Speed and Size
All figures from one virtual machine with two CPUs, Linux 6.18 on x86-64, Go 1.24.7. The servers were local, so the figures show what vpnw adds, not what a real network costs.
| Measure | Without vpnw | vpnw, sealed | What vpnw adds |
|---|---|---|---|
| Start-up and exit of /bin/true, median of 60 runs | 1.65 ms | 10.97 ms | 9.32 ms |
| The same with the env backend (proxy settings only) | 1.65 ms | 4.58 ms | 2.93 ms |
| Each new connection, 1,000 in a row, best of 3 | 0.563 ms | 1.668 ms | 1.105 ms |
| The same with the env backend | 0.563 ms | 1.348 ms | 0.785 ms |
| One 100 MB download, best of 3 | 1,251 MB/s | 789 MB/s | 63% of the bare speed |
| 64 clients in parallel, 3,008 requests of 16 KB | 2,000 requests/s | 755 requests/s | 38% of the bare rate; all 3,008 intact |
| Memory while a program runs (resident) | vpnw 4.1 MB, helper 4.2 MB |
The cost that matters for an agent is the one per connection: about a millisecond, next to the tens or hundreds of milliseconds a request to a real server takes. The parallel figure is the weakest. Every connection crosses two extra hops, from the sandbox to the helper and from the helper to the broker, and the Alpha does nothing clever about it yet.
| Build | Size | Compressed (gzip -9) |
|---|---|---|
| Linux x86-64 | 3,612,856 bytes | 1,515,249 bytes |
| Linux arm64 | 3,473,592 bytes | 1,391,935 bytes |
| macOS, Intel and Apple silicon | Compiles; not run yet | |
| Browser engine (TinyGo, WebAssembly) | 827,566 bytes | 302,498 bytes |
| Browser engine (standard Go, WebAssembly) | 4,293,029 bytes | 1,171,863 bytes |
Features and Limits
| Feature | What the Alpha supports | Limits |
|---|---|---|
| Platforms | Linux with unprivileged user namespaces, for sealed runs | macOS compiles but hasn’t run; there, only run and trace with --backend env, and guard refuses to run. No Windows |
| Programs | Programs that honor HTTP_PROXY, HTTPS_PROXY or ALL_PROXY. Run under vpnw so far: curl and Python’s urllib. Expected to work the same way, and tested in the Beta’s agent recipes: wget, git, pip, requests, httpx, Go’s net/http, Node.js 22.21 and later or 24.5 and later | A program that ignores them can’t connect when sealed. Git over SSH doesn’t use them |
| Protocols | TCP, through HTTP CONNECT, plain HTTP and SOCKS5 | UDP and QUIC are refused. No incoming connections |
| Paths | Direct; SOCKS5 or HTTP proxies, with names resolved locally or at the exit | One path per run. WireGuard, and proxies reached over TLS (https://), are Beta work |
| Policy | Names, wildcards, addresses, ranges, ports; deny_private; a default of allow or deny | No rules on URL paths or content: vpnw decides on destinations only |
| Record | Twelve event types, text or JSON Lines, schema version 1 | The schema is frozen only at v1.0 |
| learn | A draft from the last trace or any trace file | It allows what the program did, leaks included |
| Unix sockets | Refused in sealed runs; socketpair works | --allow-unix-sockets is all or nothing |
| Files | Not limited | The Beta’s file-system layer |
| Privileges | No root needed | Ubuntu 23.10 and later need an AppArmor profile, or sudo. Running as root is not recommended |
The Demo
The demo is six runs of the Alpha on Linux, recorded on September 29, 2026 with the Linux demo kit. A stand-in coding agent gets a task file with a hidden instruction to send a deploy token to an attacker, and the six steps show trace, learn, guard, a route through the office, a script that ignores proxy settings and a request for cloud credentials. The agent, the servers, the office exit, a local service and the attacker are small Python programs in a private network namespace, at addresses that exist only there.
The live demo replays those runs in the browser, line for line, and under the replay it runs the Alpha’s own Go code (the policy engine, the request plan and learn), compiled to WebAssembly with TinyGo. Two checks keep the browser honest: the request plan is compared with the running broker in 119 cases, and the TinyGo build gives the same answers as the standard Go build on 471 calls.
Each part of the demo has its own case study: the coding agent, the office route, the sealed sandbox and cloud metadata. The same demo also runs offline with the Linux demo kit, on a machine that allows unprivileged user namespaces. So far it has run on the one test machine, as root and as an ordinary user. The kit is available on request.
Where It Stands
Maturity by Part
| Part | Maturity | Evidence | Gap to close |
|---|---|---|---|
| Sealed sandbox, Linux | Working; tested on one machine | 14 of 14 ways out blocked; 6 planted bugs in the sandbox caught | IPv6, more kernels and distributions, arm64, the AppArmor profile, walls that report |
| Policy engine | Working, tested | 93.2% coverage; two fuzz targets; 9 planted bugs caught | Tools that make reviewing a policy easier |
| Broker | Working | 84.4% coverage; fuzzed; checked against the plan in 119 cases | Speed with many parallel connections |
| Paths | Direct and proxy | Path tests; a dead path is refused before start | WireGuard; switching to another exit when one is down |
| Record | Working, schema version 1 | Round-trip tests; no passwords in events | A frozen format; records that can’t be edited without it showing |
| learn | Working | 94.8% coverage | Easier review of drafts |
| macOS | Route and trace only | Compiles | guard on macOS |
| Files | Not started | None | The file-system layer |
| Packaging | A zip with the demo | The x86-64 kit ran as root and as an ordinary user on the test machine | Packages for Linux and macOS; a first run of the arm64 kit |
| Use by real agents | None | None | The Beta’s four weeks |
Readiness Level
On the European Commission’s technology readiness scale, which runs from TRL 1 to TRL 9, the Alpha sits at TRL 4, “technology validated in lab”. The engine works, and it has been tested in a lab: one machine, stand-in servers, a stand-in agent. The Beta aims at TRL 5, “technology validated in relevant environment”: real agents doing real work on the machines and CI runners where agents actually run.
How Far From a First Release
An estimate, and only an estimate: the Alpha is perhaps a quarter of the way to a first production release. The hardest design questions have working answers. The core is small, reasonably fast, and well tested on one machine. Most of the remaining work is the unglamorous part: other systems, WireGuard, limits on files, packages, an outside review and pilots. The Beta should take about 14 weeks with two to three people, and a first release about 6 to 9 months after that.
Against the Alternatives
| VPN Works Alpha | Anthropic’s sandbox runtime | vopono | |
|---|---|---|---|
| What it is | One program’s network: a path, a policy and a record | A sandbox for agents’ commands, built for Claude Code: files and network | Runs applications through VPN tunnels, each in a temporary network namespace |
| Where traffic goes | Direct, or a proxy you choose; WireGuard in the Beta | Straight out through its own proxies. Upstream proxies are not yet supported in its new configuration format | A VPN: WireGuard, OpenVPN, Cloudflare Warp or an enterprise VPN client |
| Network policy | Names, wildcards, addresses, ranges, ports and deny_private, in a fixed order | Domain allow and deny lists | None documented |
| Record of connections | Every connection with its decision, as text and JSON Lines, and learn drafts policies from it | Violation logs on macOS; on Linux, tracing by hand | None documented |
| Files | Not limited yet | Read and write limits, with protected files | None documented |
| Unix sockets | Refused, or all allowed | Refused by default. On Linux all or nothing, as in vpnw; on macOS, a list of allowed sockets | None documented |
| Platforms | Linux for sealed runs; macOS compiles, route and trace only | Linux (bubblewrap and seccomp) and macOS (Seatbelt) | Linux |
| License | Not chosen | Apache 2.0, a research preview | GPL-3.0 or later |
Bitdefender’s VPN for AI agents takes another route: a free beta for Macs with Apple silicon that sends each prompt’s traffic through its own tunnel on Bitdefender’s servers, with a broker for MCP connections.
The fair reading: Anthropic’s sandbox runtime is further along, limits files as well as the network, and uses the same kind of Linux sandbox as vpnw. vopono is mature at putting one application on a VPN, but it doesn’t decide or record anything. vpnw’s case rests on combining a path of your choice, a policy with a floor and a record that drafts the next policy, for any program that honors proxy settings, on networks a team already has. So far that is shown on one Linux machine. Sources: the sandbox runtime README and the vopono README.
Technical Risks the Alpha Revealed
- Programs that ignore proxy settings. Sealed, they fail instead of leaking, which is safe but not useful. Some agents’ tools will need recipes, and some may not work under guard at all.
- Files are shared. The sandbox covers the network. A sealed program can still read secrets its user can read and write files that run later outside the sandbox. The file-system layer is Beta work, and until then that is the widest gap.
- Silent walls. The kernel refuses a bypass attempt before vpnw hears of it, so the record shows a quiet run. The Beta tries to make the walls report.
- Ubuntu’s AppArmor rule. Ubuntu 23.10 and later restrict unprivileged user namespaces, and many agents run on Ubuntu. Without the profile the Beta will ship, sealed runs there need sudo.
- macOS. There are no network namespaces, and the system sandbox other agent tools use there is a different kind of wall. guard on macOS has to prove itself against the same bypass matrix.
- The first dependency. A user-space WireGuard path would bring the first third-party code into an engine that has none today.
- Many connections at once. Two extra hops per connection cost little one at a time, but they add up for a browser agent with dozens of connections open.
Every figure on this page was measured on the Alpha code on September 29, 2026 unless it is marked as an estimate. The scripts that reproduce them are kept with the Alpha’s source.