Run any program with only the access it was shown to need
Phobos runs an arbitrary command with only the filesystem, network and resource access that command was shown to need. It works in two phases: a discovery phase measures what a reference workload actually uses, once per runtime environment and offline, and a protected run then enforces exactly that. Grading a student submission is the use case it was written for, and an untrusted build step, a data job or a third-party tool is the same problem.
- A filesystem boundary enforced by Landlock, with no privilege, no capability and no container flag
- An outbound allow-list supervised by a seccomp connect guard, by address and port, from outside the process
- Host names enforced by an egress broker that reads the Transport Layer Security host name, and inbound connections filtered by source address
- A wall-clock timeout nothing under it can step out of
- Self-imposed resource limits on memory, processes, open files, file size and processor time
- A discovery phase that measures what a program needs instead of guessing
Phobos needs Linux, for Landlock and for seccomp user-notification. It is delivered as a container image, which compiles the four C programs and puts the shipped policy where the scripts look for it; a bare checkout is refused rather than run unprotected.
.github/scripts/assemble-run-phase-context.sh build/run-phase-context
docker compose -f docker/protecter/java/docker-compose.yaml up --buildThen wrap a command with phobos.sh, inside that image:
${PHOBOS_HOME}/phobos.sh --config exercise.cfg -- ./gradlew testRun the container with cgroup limits (--memory, --pids-limit, --cpus, and a size-bounded
--tmpfs for scratch) and whatever network isolation the deployment needs. Those are the outer
wall Phobos relies on and cannot set for itself.
phobos-cli.sh at the root of the repository is one command line for all of it. On a host it
builds the image (./phobos-cli.sh build java), runs a command in an ordinary container with
those limits and no network (./phobos-cli.sh run --exercise ./my-exercise -- ./gradlew test), and
starts the layer pruner and the recording pruner (prune, record). Inside an image it starts
what the image holds. It refuses every switch that turns a layer off; phobos.sh stays the entry
point for grading. Called on a terminal without a command, it opens a menu that asks for the
answers, runs the call they make, and prints that call so that it can be repeated without the menu.
📖 https://ls1intum.github.io/phobos/
- User Documentation: how to put a program in the sandbox, write a policy for it, and understand what Phobos does and does not protect against
- Contributor Documentation: the technologies Phobos is built on, the discovery phase and the subsystems
The documentation source lives in documentation/.
Contributions are welcome. Read CONTRIBUTING.md for the checks, the rules for changing the sandbox and the discovery phase, and the pull request process, and AGENTS.md for the conventions a change here is held to. Participation is governed by our Code of Conduct.
Found a security vulnerability? Please do not open a public issue; follow SECURITY.md.
If you use Phobos in your work, please cite it using the metadata in CITATION.cff.
Phobos is licensed under the MIT Licence. See LICENSE for details. It is designed to sit beneath Ares 2, which guards the language runtime the operating system cannot see, and inside a container that supplies the hard resource caps.