Admin panel¶
The admin panel lives at /admin/ and is restricted to users with
is_admin = true. Every action you take in the panel writes a signed entry
to the audit chain.
Logging in as admin¶
Log in with the admin account at /auth/login. The admin credentials are
seeded from the ADMIN_USERNAME and ADMIN_PASSWORD environment variables
on first run. Once logged in, the /admin/ prefix is accessible; non-admin
users who attempt to reach it receive a 403.
Dashboard (/admin/)¶
The dashboard gives you a live operational snapshot:
Core stats row
- Total users, teams, challenges (total and visible)
- Total submissions and solves
Activity row (time-windowed)
- Submissions in the last hour / last 24 hours
- Solves in the last hour
- Active users in the last hour (based on
USER_LOGINaudit events) - Running container instances
- New registrations in the last 24 hours
Security row
- Wrong flag attempts (total and last hour)
- Banned users
- Unique IPs seen (total, from logins, from instance spawns)
Challenge solve breakdown
- Top 5 most-solved visible challenges
- Bottom 5 least-solved visible challenges
Event breakdown
- Top 10 event types by count in the last 24 hours
- Severity totals (INFO / WARNING / CRITICAL) across all time
Running instances panel
Lists every instance currently in running state, sorted by expiry time.
From here you can extend an instance's window.
Score adjustment
A quick form at the bottom of the dashboard lets you apply a manual point
adjustment (+ or -) to any Principal. You must supply a reason; the
adjustment is recorded as a MANUAL_SCORE_ADJUST WARNING event.
Scoreboard freeze toggle
A single button freezes or unfreezes the public scoreboard. The frozen state
persists in the Flask-Caching layer until the app restarts or you unfreeze it.
Freeze events are logged as SCOREBOARD_FREEZE_TOGGLED.
Docker telemetry panel
When LAB_DOCKER_HOST is configured, the dashboard shows per-container CPU,
memory, and network I/O for every running instance. If the Docker host is
unreachable the panel reports "unavailable" without crashing the dashboard.
WireGuard telemetry panel
When WireGuard is configured, the dashboard shows connected peers, expected peers per lease, and any stale peers (peers with no known lease).
Two action buttons appear:
- Reconcile VPN peers — re-syncs all WireGuard peer configs from the instance metadata. Use this if peers went stale after a restart.
- Test VPN access — probes the WireGuard interface and reports status.
Challenges (/admin/challenges)¶
A table of all challenges, sorted by category then point value, with status badges (Visible / Hidden). From this page you can:
- Toggle visibility — makes a hidden challenge visible (or vice versa).
When a challenge becomes visible, flags are pre-generated for all active
Principals. Logged as
CHALLENGE_TOGGLED. - Generate files — runs the challenge workspace generator with an admin-preview flag. Useful for checking that the importer and build scripts work before exposing the challenge to players.
- Navigate to edit or delete.
Create a challenge (/admin/challenges/new)¶
Fields:
| Field | Notes |
|---|---|
| Title | Max 200 characters |
| Slug | URL-safe identifier, must be unique |
| Category | One of: crypto, web, pwn, misc, osint, rev, forensics |
| Description | Markdown rendered at display time |
| Points | 1–10000 |
| Flag prefix | Defaults to the server's DEFAULT_FLAG_PREFIX (e.g. GRIZZ) |
| Requires container | Enables the dynamic-challenge fields below |
| Container image | Docker image reference |
| Container port | Port the container listens on (1–65535) |
| Service scheme | http, ws, ftp, gopher, ssh |
| Port transport | TCP / UDP / SCTP |
| Lab stack JSON | Full multi-service stack spec (optional, validated against ChallengeStackSpec) |
| Status | Hidden (default) or Visible |
| Attachments | Files served to players; allowed types include common binary, source, and document formats |
Saving a visible challenge pre-generates flags for all active Principals.
Logged as CHALLENGE_CREATED.
Edit a challenge (/admin/challenges/<id>/edit)¶
Same fields as create. If you change a challenge from Hidden to Visible,
flags are generated for all active Principals at save time. Logged as
CHALLENGE_UPDATED.
Delete a challenge¶
Deletes the challenge row and all associated submissions, solves, flags, and
uploaded files. The event log challenge reference is nulled (events are not
deleted). Logged as CHALLENGE_DELETED at WARNING severity.
YAML import (/admin/challenges/import)¶
Upload one or more .yaml / .yml files and CTFHive parses each one through
the challenge importer (ctfapp/services/challenge_importer.py). The results
page shows per-file status: ok, skipped, or error with a reason.
The full YAML schema is documented at
Challenge format. Import activity is logged as
CHALLENGES_IMPORTED.
Users (/admin/users)¶
A table of all users, sorted by registration date (newest first). For each user you can:
- Toggle admin — grants or revokes
is_admin. You cannot toggle your own admin status. Logged asADMIN_TOGGLEDat WARNING severity. - Ban / unban — sets
stateto"banned"or"active". Banned users cannot log in. You cannot ban yourself. Logged asUSER_BAN_TOGGLEDat WARNING severity.
Appearance (/admin/appearance or /admin/theme)¶
Limited customization
See Theming for a precise description of what is and is not configurable.
The appearance page exposes the UI knobs that do work. Theme, layout, and font-pack switching are preserved as stubs in the codebase for backward compatibility but currently only one choice exists for each. The functional controls are UI density and UI motion (and by extension the background animation, set via Site Settings).
Audit log (/admin/events)¶
A paginated view of the event_log table, newest first. Filter by:
- Severity: ALL / INFO / WARNING / CRITICAL
- Event type: substring search (e.g.
FLAG,USER_LOGIN)
Each entry shows: timestamp, severity badge, event type, actor user ID, principal ID, challenge ID, and the JSON payload.
The audit log is tamper-evident. The Verify chain button at the top of
the page (/admin/events/verify-chain) re-walks every entry and checks that
each entry's HMAC signature matches its recomputed value. If the chain is
intact you get a green confirmation flash. If any entry has been modified or
deleted since it was written, the flash reports the first bad event ID.
See Audit chain for the technical details of how the chain is constructed.
Site settings (/admin/settings)¶
These global settings are stored in the app_settings table and cached in
memory for 5 minutes.
| Setting | Default | Description |
|---|---|---|
max_team_size |
4 |
Maximum members per team (enforced at join time) |
default_bg_animation |
matrix |
Background animation shown to new visitors |
allow_solo_play |
true |
Allow players to create solo Principals |
allow_team_switch |
true |
Show the solo-to-team switch option |
registration_open |
true |
Allow new user registration |
Changing any setting is logged as SETTINGS_UPDATED.
Background animation choices¶
| Value | Description |
|---|---|
matrix |
Matrix rain (canvas) |
particles |
Particle network (canvas) |
mrrobot |
Mr. Robot effect (canvas) |
binary |
Binary rain (canvas) |
hexgrid |
Hex grid pulse (canvas) |
starfield |
Starfield warp (canvas) |
circuit |
Circuit board (canvas) |
rain |
Rain drops (canvas) |
fireflies |
Fireflies (canvas) |
topography |
Topographic map (canvas) |
dna |
DNA helix (canvas) |
waveform |
Audio waveform (canvas) |
glitch |
Glitch effect (canvas) |
constellation |
Constellation (canvas) |
plasma |
Plasma — GPU-accelerated (WebGL) |
aurora |
Aurora borealis — GPU-accelerated (WebGL) |
nebula |
Nebula — GPU-accelerated (WebGL) |
voronoi |
Voronoi flow — GPU-accelerated (WebGL) |
electric |
Electric storm — GPU-accelerated (WebGL) |
fluid |
Fluid gradient — GPU-accelerated (WebGL) |
none |
No animation |
GPU animations require WebGL support in the player's browser. Fall back to a canvas option if you are unsure about your audience's hardware.
Audit events written by the admin panel¶
| Event | Severity | Trigger |
|---|---|---|
CHALLENGE_CREATED |
INFO | New challenge saved |
CHALLENGE_UPDATED |
INFO | Challenge edited |
CHALLENGE_TOGGLED |
INFO | Visibility toggled |
CHALLENGE_DELETED |
WARNING | Challenge deleted |
CHALLENGES_IMPORTED |
INFO | YAML import completed |
INSTANCE_EXTENDED |
INFO / WARNING | Instance time window extended |
ADMIN_TOGGLED |
WARNING | Admin status changed |
USER_BAN_TOGGLED |
WARNING | User banned or unbanned |
MANUAL_SCORE_ADJUST |
WARNING | Manual point adjustment |
SCOREBOARD_FREEZE_TOGGLED |
WARNING | Scoreboard frozen or unfrozen |
SETTINGS_UPDATED |
INFO | Site settings saved |
THEME_CHANGED |
INFO | Active theme changed |
LAYOUT_CHANGED |
INFO | Active layout changed |
FONT_PACK_CHANGED |
INFO | Active font pack changed |
UI_DENSITY_CHANGED |
INFO | Density mode changed |
UI_MOTION_CHANGED |
INFO | Motion mode changed |
PRESET_APPLIED |
INFO | Appearance preset applied |
VPN_RECONCILED |
INFO / WARNING | WireGuard peer reconcile run |
VPN_ACCESS_TESTED |
INFO / WARNING | WireGuard access probe |