What is vulnboxd?
vulnboxd runs on your vulnbox during an attack-defense CTF and takes care of the services on it: it sets the box up for your team, deploys your patches, filters the traffic that reaches the services, and watches them, rolling a change back when it breaks one. It is purely defensive.
It comes as two programs — vulnboxd, the daemon systemd runs, and vulnboxctl, for everything a team does by hand — plus vulnboxd-pcap, the capture broker, if you turn it on.
Setting up the box
At the start of a game, vulnboxctl setup-interactive (or vulnboxctl init from a script) prepares everything in one go, for all services in parallel:
- A git repository per service, with the current state committed, large files kept out, and the branch named
main. - A private GitHub repository per service, each with its own deploy key, pushed and set up so
git pushworks from the service directory, by hand as well. - Configuration for the capture tools:
tulip.jsonandshovel.yaml, listing every published service port. - vulnboxd itself: the binaries, its config, a systemd unit and a guard in front of
docker compose, started.
It is safe to run again. A service that failed can be fixed and retried without touching the others, and an optional webhook reports when a run starts and finishes.
During the game
It knows the game. A game mode for FAUST CTF 2026 or the ECSC 2026 brings the flag format, the tick timing and the vulnbox address, and reads the checker's verdict on each service from the gameserver.
It finds your services. Every directory under /srv (configurable) with a compose file is a service, the way FAUST CTF lays out its vulnboxes. vulnboxd reads each compose file, after .env and environment substitution, to learn which ports are public, and picks up new services as they appear.
It deploys your patches. vulnboxd polls each service's git repository. As soon as one changes, it builds and pulls the new images while the old version keeps serving, and swaps the containers in the last few seconds of the tick (a window of 5 seconds by default). While a container restarts, the proxy holds new connections instead of refusing them, so a deploy that runs over shows up as a slow request rather than a failed check.
It filters their traffic. Every public port is moved behind a proxy inside vulnboxd, which applies the rules in the service's vulnboxd-rules.yml:
- Block, rewrite, stall or log tcp, udp, http (including h2c and WebSockets), ftp and dns traffic, matched as it streams by, at any distance, in constant memory.
- Edited through git and reloaded within a second, with a bypass header so your own exploits still get through. Rules covers the rest: flag egress, routing, mirroring and the cookbook.
It rolls back what breaks. A new version that does not come up, or a change after which the checker says down, is undone with a commit that is pushed, and deployed. vulnboxctl rollback does the same by hand.
It keeps the rules with the team. Each service's rules file is created for it, committed and pushed, so everyone edits rules through git. Saving the file reloads the rules within a second, without a rebuild or a dropped connection; a broken file is reported and the previous rules stay.
It tells you what is happening. Alerts go to a Discord webhook when a port stops answering, the checker says down, a build or deploy fails, or something is rolled back. vulnboxctl top is a terminal dashboard of services, ports, connections and which rules are firing, and the same numbers are served as Prometheus metrics. A rule set to action: log shows what it would block before you let it.
What it does not do
It is worth knowing the edges before you put it on a box ten minutes before a game:
- No attacking. No exploits, no flag submission, nothing to help with your own attack tooling. It only ever stands between other teams and your services.
- No host hardening. It does not firewall the box, manage users or patch your packages. It filters the ports your services publish, and nothing else.
- GitHub-shaped setup.
initcreates repositories and deploy keys on GitHub. Any other remote works, but you pointoriginat it yourself. - One box. It manages the services on the machine it runs on; nothing is shared between vulnboxes.
- x86_64 releases. Built for glibc on x86_64; anything else is a
cargo build --releaseaway.
Next steps
- Getting started sets up a box from scratch.
- How it works explains what vulnboxd does to your services and when.
- Rules explains what you can filter and how, and the cookbook has rules ready to paste.