Exit
Exit is the fifth engine of VPN Works, the far end of the tunnel. Partners and internal systems often let traffic in by IP address, so AI agents and CI jobs need fixed addresses to leave from. Exit runs on a server with fixed addresses and gives each client its own. A plain proxy trusts whatever reaches it, so a hijacked client can push anything through. Exit decides each request again with the client’s own policy before it connects, and keeps a record of every connection that joins up with the record on the client’s side.
VPN Works keeps network access narrow and on the record. The Agent gives each AI agent a network of its own. Scope gives each person on a company VPN only the systems they use. Lab checks that VPN apps keep traffic inside the tunnel when things go wrong. Ledger makes every record tamper-evident. Exit checks the policy again at the far end.
Exit works with the Agent. Agent 0.2.0 reaches exits over TLS, moves to the next exit in its list when one stops answering, and sends the IDs of its run and of each connection with every request, so the two records join.
Exit 0.1.0 is an Alpha: a working engine, tested on one Linux machine in private test networks, with the real Agent and real TLS. No exit has run on a real public address yet.

Try It
The demo below replays a recorded run: two agents, and two exits in two “countries”, exit-de and exit-nl. A partner lets the agents in by address. One agent asks for things its policy refuses, a script with a stolen token asks an exit directly, and then exit-de is killed partway and traffic moves to exit-nl. The page runs Exit’s own Go code, compiled to WebAssembly, so you can edit a client’s policy and see the exit decide. Nothing you do in it leaves your browser.
The demo has more room on its own: open it full screen.
What the Demo Shows
| Step | What happens |
|---|---|
| Two agents, two exits | exit-de and exit-nl, with three clients each, and the 4 fixed addresses the partner allows |
| Fixed addresses | 4 requests through exit-de. The partner sees agent-1 arrive from 198.51.100.10 every time, and agent-2 from 198.51.100.11 |
| Checked at both ends | agent-1 asks for attacker.test, and the Agent refuses, so nothing leaves. It asks for intranet.partner.test: the Agent allows the name, and the exit refuses it, having seen it point to 10.50.0.5 |
| A tampered client | A script with agent-2’s token asks exit-de for the cloud metadata address, attacker.test and the intranet. All 3 are refused, and nothing reaches a server |
| An exit fails | exit-de is killed. Each agent’s next connection moves to exit-nl and is open 5 and 9 ms after its dial began. No request fails, and the partner now sees 203.0.113.10 and 203.0.113.11 |
| One joined record | 9 of 9 connections that reached an exit join the exits’ records on the run and connection IDs |
The fixed exit case study walks through it step by step.
How It Works
- Over TLS. HTTP CONNECT and SOCKS5, both inside TLS, and the Agent always checks the exit’s certificate. A client is known by its token, and the exit keeps only the token’s SHA-256.
- Decided again. The exit reads the client’s policy with the Agent’s own configuration reader and decides with the Agent’s own code, before it dials anything. Names resolve at the exit, so a name that points into a private range is refused there.
- Fixed addresses. An address per client, or a pool that clients share. A client can’t leave from an address that isn’t its own.
- Failover. The Agent’s path can name a list of exits. The health check before the start picks the first that answers. When it stops answering, new connections move to the next one, and an event records the switch.
- One record. Both ends write the Agent’s event format, tagged with the client’s run and connection IDs, and
vpnw-exit joinmatches the two.
What Was Measured
| Figure | What it means |
|---|---|
| 110 of 110 | Requests decided the same way by the Agent and by an exit, with the same rule and reason, under 5 policies. The real vpnw, sealed, against the real vpnw-exit |
| 0 of 11 | Forbidden requests that reached a server when a tampered client with a valid token sent them straight to an exit |
| 3 ms | From the start of a connection to having it open through the second exit, when the first exit’s process had been killed. An exit that goes silent costs the list’s limit, 3 seconds |
| 2.0 ms | Time an exit added to each new connection, with a full TLS handshake. With a resumed TLS session, 1.7 ms |
| 22 of 22 | Deliberately planted bugs caught by Exit’s tests |
One 100 MB download ran at 777 MB/s through an exit, and each connected client took 58 KB of the exit’s memory. All figures come from one machine with two CPUs, Linux 6.18 on x86-64. Exit is written in Go with the standard library only, and its Linux program is 5.7 MB.
Agent 0.2.0
Exit needed three small changes in the Agent, and they became Agent 0.2.0: proxies over TLS, a list of exits with failover, and the run’s ID sent to the exit. Nothing else changed in what the Agent does, and the checks that cover what 0.1.0 had came out as they did on September 29: 14 of 14 ways out of the sealed sandbox were blocked. The tests caught every planted bug, the Alpha’s 24 and 15 new ones in the new code. The Agent 0.2.0 note has the details.
Limits
- Real exits. No exit has run on a real public address yet, and no WireGuard tunnel took part. The two countries are network namespaces on one machine.
- A stolen token. The exit can’t tell a stolen token from its client. The policy limits what the token can reach, and the record shows its use.
- After a failover the partner sees another address, so it has to allow every exit’s address for a client.
- TCP only, and IPv4 only so far. During a run the Agent doesn’t move back to an exit that recovers.
The Code
VPN Works is open source under the Apache License 2.0. Copyright VPNW.com 2026. The code is at https://github.com/VPNWorks/vpnw. The Exit Alpha report has every test and figure, and the commands that reproduce them.
What Comes Next
Exits on real public addresses, with WireGuard to them, certificates and tokens that can change without a restart, IPv6, and records collected from several exits. Then a pilot with a partner that lets traffic in by address. The roadmap has the plan for every engine. Teams whose agents or CI jobs need fixed addresses are welcome to write.