OSCTF

module
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2026 License: Apache-2.0

README

OSCTF

An open, self-hostable platform for running cybersecurity competitions, labs, and training.

What makes it different: most CTF platforms hand every team the same shared challenge instance. OSCTF gives each team its own isolated container — its own port, its own network, an optional per-team unique flag — created on demand and lifecycle-managed by a built-in scheduler (TTL, extend, per-team quota, automatic teardown at event end). That per-team-instance model, not the scoreboard, is the reason to use it over a CTFd-class tool.

Network isolation is enforced on Linux only. On Docker Desktop (macOS/Windows) per-team containers are reachable across networks when ports are published — isolation is not enforced there. Run real events on a Linux host. Detail: docs/v0.2/03-runtime.md · issue #2.

CTFs are the entry point; the durable goal is to be the open infrastructure layer universities, communities, and companies build their security education on. Vision and roadmap: docs/project-desc.md.

Quick start

git clone https://github.com/swayam-mishra/OSCTF && cd OSCTF
cp .env.example .env

# Change OSCTF_ADMIN_PASSWORD (default: change-me-now) before exposing this to anyone.

# On Linux, give the platform access to the host Docker socket group, or every
# container challenge fails at instance-start time (Docker Desktop can skip this):
echo "OSCTF_DOCKER_GID=$(stat -c '%g' /var/run/docker.sock)" >> .env

docker compose up -d --build --wait

Then open http://localhost:8080: authentication, teams, a challenge board with seeded examples, flag submission with scoring, a live scoreboard, and an admin panel. No cloud account, no license key, no external services.

The platform mounts the host Docker socket to launch challenge containers, which is root-equivalent on the host. Run events on a dedicated host/VM. See docs/v0.1/08-challenge-runtime.md.

Running a real event

The quickstart is fine for a local trial; before an actual event, read docs/v0.1/10-deployment.md. The notes people most often miss:

  • Linux host — for the per-team isolation above, and set OSCTF_DOCKER_GID to the socket's group.
  • Large scoreboards — each live scoreboard WebSocket is a file descriptor; OSCTF_WS_MAX_CONNS is clamped to RLIMIT_NOFILE, so raise the host ulimit (e.g. LimitNOFILE=65536) and size the cap accordingly for a few thousand viewers.
  • Shared-NAT venues — the per-IP register/login limits default generous so a campus or venue behind one NAT can all sign in at event start; tighten OSCTF_REGISTER_IP_* / OSCTF_LOGIN_IP_* for a public-internet deployment.
  • Instance tuningOSCTF_INSTANCE_TTL / _EXTEND / _MAX_TTL / _REAP_AFTER, OSCTF_TEAM_INSTANCE_QUOTA, OSCTF_PORT_RANGE_START / _END (default 3000032767, which must be open on the host). All settings are documented in .env.example.

Local development

make setup      # install pinned tools + dashboard deps
make dev        # start Postgres, Redis, MinIO (compose)
make dev-api    # run the Go API on :8080
make dev-web    # run the Vite dev server on :5173 (proxies /api -> :8080)

Tests

make test              # unit (Go -short + web)
make test-integration  # integration (testcontainers spin up Postgres/Redis/MinIO)
make smoke             # build the stack, run the end-to-end smoke test, tear down

The testing tiers, build tags, and the invariants they pin are described in AGENTS.md; CI runs all of it (plus a compose smoke and Playwright e2e) on every push.

Layout

Path What
api/ Go backend (modular monolith): HTTP, services, stores, challenge runtime, scheduler
dashboard/ React + TypeScript SPA (Vite)
examples/ Seeded example challenges (challenge.yaml format)
deploy/ Prometheus / Grafana / Caddy configs (optional compose profiles)
docs/ Versioned build specs (v0.1v1.0) + guides — start at docs/README.md
scripts/ Smoke test and dev helpers

Status

Latest release: see Releases and the CHANGELOG. Shipped so far: v0.1 (MVP) → v0.2 (per-team instances + scheduler), hardened across v0.2.1 (security) and v0.2.2 (concurrency).

Next: v0.3 — a plugin system (auth / scoring / notifications / challenge types) and a stable, semver-governed API v1 — is fully specified in docs/v0.3/ and docs/v0.3.1/, but not yet built. The HTTP surface is still /api/v0; there are no API stability promises before v1.0.

License

Apache License 2.0. Contributions are accepted under the same license (see NOTICE).

Directories

Path Synopsis
examples
challenges/cookie-monster/src command
cookie-monster: sets a role=guest cookie; a role=admin cookie reveals the flag.
cookie-monster: sets a role=guest cookie; a role=admin cookie reveals the flag.
challenges/env-hunter/src command
env-hunter proves the platform injects FLAG at runtime: the image ships with no flag baked in; /debug?var=FLAG reads it from the environment.
env-hunter proves the platform injects FLAG at runtime: the image ships with no flag baked in; /debug?var=FLAG reads it from the environment.
challenges/hardening-demo/src command
hardening-demo serves its flag at / and lets players observe the v0.2 runtime hardening: a read-only rootfs with only /tmp and declared writable_paths (/data) writable, dropped capabilities, and no network egress.
hardening-demo serves its flag at / and lets players observe the v0.2 runtime hardening: a read-only rootfs with only /tmp and declared writable_paths (/data) writable, dropped capabilities, and no network egress.
challenges/per-team-pwn/src command
per-team-pwn is a tiny TCP service that hands over the per-instance FLAG once the client sends the magic word.
per-team-pwn is a tiny TCP service that hands over the per-instance FLAG once the client sends the magic word.
challenges/per-team-web/src command
per-team-web serves a per-team, per-instance flag.
per-team-web serves a per-team, per-instance flag.
challenges/robots-rule/src command
robots-rule: a tiny stateless web app.
robots-rule: a tiny stateless web app.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL