Skip to content

Releases: tbcsec/Flagpost

Flagpost v1.3.0 — SAML & LDAP sign-in, encrypted secrets & venue mode

Choose a tag to compare

@tbcsec tbcsec released this 04 Aug 22:07

Flagpost v1.3.0 — external authentication rounded out (SAML + LDAP), secrets encrypted at rest, and a set of presentation and hardening improvements. All nine milestone issues shipped.

Pushing this tag builds and publishes the versioned GHCR images; source builds now report 1.3.0-src.

Authentication

  • SAML 2.0 identity providers (#100) — SP-initiated login as a second redirect kind on the ADR-0022 provider framework: signature-before-trust via python3-saml, InResponseTo/replay/XSW defences, persistent-NameID requirement, and an SP-metadata endpoint.
  • LDAP / Active Directory (#101) — the first non-redirect kind: a directory bind inside POST /api/auth/login, tried only after local password verification fails, so the break-glass owner never touches a directory and an outage never locks everyone out. TLS-mandatory with certificate validation, RFC 4515-escaped search, stable-id subject (never the DN), closed-posture email that can't hijack a local account by default, and the bind run off the event loop under a timeout.
  • External-identity admission policy (#118) — a per-provider trust posture (open/closed): public IdPs still pass the registration-open + email-domain gate, while an admin-configured directory is admitted by being enabled, closing the unverified-email account-takeover hole.

Security & hardening

  • Encrypted-at-rest facility for retrievable secrets (#109) — Fernet-backed EncryptedString (ADR-0020); the SMTP password, OIDC client secret, SAML SP key and LDAP bind password are all stored encrypted and stay out of portable backups.
  • Logo upload magic-byte check (#114) — uploads are content-sniffed (PNG/JPEG/GIF/SVG) rather than trusted by extension or content-type.
  • Single owner-provisioning helper (#133) — all owner-creation paths funnel through one helper that stamps setup_completed_at, so an install can't be left half-configured.

Presentation

  • Alternative challenge list view (#55) — a compact list alternative to the card grid, remembered per user.
  • Venue / projector mode (#77) — a big-screen public view for live events (scoreboard, first-blood splashes, insights).
  • Tabbed profile layout (#113).

Upgrade notes

No manual migration steps — alembic upgrade head runs on boot as usual, and the release adds no destructive schema changes. LDAP and SAML providers are configured under Admin → Site settings → Auth; both are optional and off until an administrator adds one.

Full changelog: v1.2.0...v1.3.0

Flagpost v1.2.0 — SSO, self-service accounts & a security release

Choose a tag to compare

@tbcsec tbcsec released this 01 Aug 22:24

The v1.2.0 milestone — external identity, self-service account management, and staff tooling — and a security release. Upgrading is strongly recommended for every deployment.

🔒 Security

Seven fixes, four of them tracked as GitHub Security Advisories. The advisories affect v1.1.1 and earlier; the three OIDC/config fixes land features that had not shipped in a tagged release, so they affect source builds only.

Advisory Severity Summary
GHSA-ccm4-9573-9965 High The first-run setup wizard could be re-entered on a live install once its active-admin count hit zero, letting an anonymous visitor mint a global Administrator.
GHSA-mgh6-f2j7-rv64 High A delegated manage_roles holder could self-escalate to full Administrator — no check compared a granted permission set against the actor's own.
GHSA-rjmr-qp7p-5gp8 High Concurrent flag submissions bypassed both the one-solve-per-subject rule and the multiple-choice guess cap, inflating scores.
GHSA-q69m-7mgh-r2gh Medium Scoreboard freeze filtered only /scoreboard; four other endpoints served live solve data, so a frozen board could be reconstructed.

Also hardened, on the current development line:

  • OIDC JIT provisioning no longer grants a site-wide role (#129). A just-in-time SSO user was assigned Participant with no competition scope, which the permission layer reads as every competition — exposing private competitions and their invite codes. Now matches local registration (no assignment until join).
  • The backend refuses to boot on MinIO's default credentials when reachable (#130), rather than silently serving an internet-exposed object store on minioadmin/minioadmin.
  • Credential endpoints are rate-limited (#131) — login, registration, password reset and email verification previously had no throttle — the SSRF blocklist now covers RFC 6598 shared address space (cloud metadata on CGNAT), and the refresh cookie ships Secure on the production stack.

✨ Features

  • OIDC / OAuth2 single sign-on (#58) — bring your own identity provider (Google, Okta, Keycloak, Entra, or any discovery-document IdP), with local login surviving as break-glass.
  • Support ticket attachments (#80) — screenshots on tickets, sniffed and sandbox-served.
  • Self-service email (#106) — add, change, or clear your address; admin-toggleable email verification (#74); and an email-domain allowlist for public registration (#56).
  • Personal API tokens (#75) — flp_-prefixed, self-minted, full effective permissions.
  • Rules / code of conduct (#57) — authored rich text with a join gate and recorded acceptance.
  • Submissions browser (#76) — a staff dispute-resolution view of raw submissions on /analytics, behind its own narrow permission.
  • Daily update check + anonymous adoption count (#111) — a version-only check driving the admin update notice; off switch in settings and via env for air-gapped installs.

⬆️ Upgrading from v1.1.1

Migrations run automatically on start (docker compose up) — no manual steps. Two notes:

  • Scores may change where the submission race (GHSA-rjmr-qp7p-5gp8) had already inflated them. The dedupe migration keeps the earliest awarded solve per subject and demotes the rest, matching what the scoreboard displayed. To see whether an event was affected before upgrading, look for a subject with more than one awarded row on a challenge.
  • Set real MinIO credentials before upgrading a reachable deployment (MINIO_ROOT_USER / MINIO_ROOT_PASSWORD), or the backend will now refuse to start — see #130 and the README "Deploying to production" section. Localhost runs are unaffected.

What's Changed

📦 Dependencies

  • chore(deps): Bump actions/checkout from 4 to 7 by @dependabot[bot] in #2
  • chore(deps): Bump docker/build-push-action from 6 to 7 by @dependabot[bot] in #8
  • chore(deps): Bump docker/setup-buildx-action from 3 to 4 by @dependabot[bot] in #9
  • chore(deps): Bump the backend-deps group across 1 directory with 19 updates by @dependabot[bot] in #5
  • chore(deps): Bump node from 20-alpine to 26-alpine in /frontend by @dependabot[bot] in #7
  • chore(deps): Bump actions/setup-node from 4 to 7 by @dependabot[bot] in #3
  • chore(deps): Bump python from 3.12-slim to 3.14-slim in /backend by @dependabot[bot] in #1
  • chore(deps): Bump actions/setup-python from 5 to 7 by @dependabot[bot] in #4
  • chore(deps): Bump docker/login-action from 3 to 4 by @dependabot[bot] in #61
  • chore(deps): Bump the frontend-deps group in /frontend with 6 updates by @dependabot[bot] in #62
  • chore(deps-dev): Bump @testing-library/jest-dom from 6.9.1 to 7.0.0 in /frontend by @dependabot[bot] in #66
  • chore(deps): Bump the tiptap group in /frontend with 4 updates by @dependabot[bot] in #69
  • chore(deps): Bump tailwind-merge from 2.6.1 to 3.6.0 in /frontend by @dependabot[bot] in #70
  • chore(deps-dev): Bump @types/node from 22.20.1 to 26.1.1 in /frontend by @dependabot[bot] in #71
  • chore(deps): Update fastapi requirement from <1.0,>=0.140.0 to >=0.140.7,<1.0 in /backend by @dependabot[bot] in #93
  • chore(deps-dev): Bump @types/node from 26.1.1 to 26.1.2 in /frontend in the frontend-deps group by @dependabot[bot] in #95
  • chore(deps): Bump the tiptap group in /frontend with 4 updates by @dependabot[bot] in #94
  • chore(deps-dev): Bump jsdom from 25.0.1 to 30.0.0 in /frontend by @dependabot[bot] in #96
  • chore(deps-dev): Bump typescript from 5.9.3 to 6.0.3 in /frontend by @dependabot[bot] in #97
  • chore(deps): Update fastapi requirement from <1.0,>=0.140.7 to >=0.140.13,<1.0 in /backend by @dependabot[bot] in #121
  • chore(deps): Bump the tiptap group in /frontend with 4 updates by @dependabot[bot] in #122

🧹 Other Changes

  • chore(deps): dependabot npm/pip groups take minor+patch only; majors go individual by @tbcsec in #60
  • chore(ci): test the runtimes the images ship — python 3.14, node 26 by @tbcsec in #67
  • chore(deps): dependabot lockstep group for @tiptap/* by @tbcsec in #68
  • Plan: [Feature]: submissions browser by @tbcsec in #84
  • Plan: [Feature]: rules/code of conduct by @tbcsec in #83
  • Plan: [Feature]: alternative challenge view by @tbcsec in #82
  • fix(collab): restore list styling in the rich-text/collab editors by @tbcsec in #85
  • fix: survey submission returns 204 instead of an empty-bodied 201 by @tbcsec in #86
  • fix(editors): hoist ToolbarButton (static-components ×9) + restore live toolbar active states by @tbcsec in #88
  • fix(hooks): eliminate 14 set-state-in-effect warnings (#38 batch 2/3) by @tbcsec in #89
  • fix(hooks): clear last react-hooks warnings + promote 5 rules to error (#38 batch 3/3, closes #38) by @tbcsec in #90
  • chore(deps): ignore typescript >=7 until typescript-eslint supports it (#91) by @tbcsec in #92
  • Submissions browser: staff dispute-resolution tab on /analytics by @tbcsec in #99
  • Email domain allowlist for public registration by @tbcsec in #102
  • Rules / code of conduct: authoring, join gate, recorded acceptance (#57) by @tbcsec in #103
  • fix(automations): style the condition field picker by @tbcsec in #107
  • Admin-toggleable email verification (#74) by @tbcsec in #108
  • docs(adr): ADR-0020 — hash what is only verified, encrypt what must be retrieved by @tbcsec in #110
  • Personal API tokens (#75) by @tbcsec in #112
  • refactor(admin): tab the Site settings page, fold Appearance into it (#104) by @tbcsec in #115
  • Support ticket attachments (#80) by @tbcsec in #116
  • Self-service add / change / clear email (#106) by @tbcsec in #117
  • OIDC / OAuth2 external identity (#58) by @tbcsec in #119
  • Daily update check + anonymous adoption count (#111) by @tbcsec in #123
  • Source builds report a version instead of "dev" by @tbcsec in https://gi...
Read more

Flagpost v1.1.1 — Versioned images & compose fix

Choose a tag to compare

@tbcsec tbcsec released this 26 Jul 14:27
0727f16

A small patch on the heels of v1.1.0:

  • Version-tagged images: every release now publishes pinned images to GHCR — ghcr.io/tbcsec/flagpost-{backend,frontend}:v1.1.1 (and :latest). The frontend is built in same-origin mode (no baked-in domain), so one image works behind any single-origin proxy — pull by tag instead of building from source. See the README's "Versioned images" section.
  • Fix: a fresh docker compose up crash-looped the backend when DEMO_MODE was unset (empty string isn't a valid bool). Now defaults to false.

What's Changed

🚀 Features

  • feat(deploy): version-tagged release images + same-origin frontend mode by @tbcsec in #54

Full Changelog: v1.1.0...v1.1.1

Flagpost v1.1.0 — Live updates, targeted announcements & more

Choose a tag to compare

@tbcsec tbcsec released this 26 Jul 11:41
96e1eb4

The first feature release since going public — driven almost entirely by issues filed against the platform in its first days.

Highlights

  • Live updates across the site — a per-competition activity channel keeps dashboards, challenge cards, rosters, and analytics moving in real time, no refresh needed.
  • Expanded announcements — urgency levels (info / warning / critical), audience targeting to specific teams or users, bell notifications, and a refreshed banner + notification centre.
  • Public spectator insights — stat tiles, highlights, and a top-10 points-over-time timeline on the public scoreboard.
  • Judge-question analytics cards — least solved, most attempted, most tickets, most first bloods, at a glance.
  • Archived-competition retention — optional auto-delete after a configurable window (default 30 days), with structural protection for pre-existing archives.
  • Personal challenge scratchpad — solo competitors get the live CRDT notes pad that was previously team-only.
  • Richer scoreboard chart — per-bar labels and a detail tooltip on hover/focus.
  • Plus sortable/searchable/paginated tables platform-wide, themed scrollbars, and a round of bug fixes.

Upgrading from v1.0.0: two additive DB migrations run automatically on start (docker compose up); no manual steps, no breaking changes.

What's Changed

🚀 Features

  • feat(ui): reusable data-table — sort, search, pagination by @tbcsec in #28
  • feat(ui): data-table rollout — scoreboard, users, roles, challenges by @tbcsec in #29
  • feat(ui): themed scrollbars via design tokens by @tbcsec in #30
  • feat(public): spectator insights + points timeline by @tbcsec in #35
  • feat(realtime): live updates across the site — the activity room by @tbcsec in #36
  • feat(analytics): judge-question insight cards by @tbcsec in #39
  • feat(retention): archived-competition auto-delete by @tbcsec in #41
  • feat(announcements): severity ladder, audience targeting + UI pass by @tbcsec in #44
  • feat(collab): personal challenge scratchpad for individual mode by @tbcsec in #47
  • feat(scoreboard): contextual top-10 chart — labels + detail tooltip by @tbcsec in #53

🐛 Bug Fixes

  • fix(demo): first-blood announcement uses the lightning-bolt idiom by @tbcsec in #31
  • fix(announcements): banner auto-dismisses after a 30s dwell by @tbcsec in #32
  • fix(automations): resolve friendly template fields ({user_name}, {challenge_title}, …) by @tbcsec in #33
  • fix(build): hoist the clock read out of render (unbreaks the image build) by @tbcsec in #43
  • fix(shell): stop a long email pushing "Sign out" out of the sidebar by @tbcsec in #50
  • fix(ui): dark-mode-correct, right-aligned date picker indicators by @tbcsec in #51

📦 Dependencies

  • chore(deps): eslint-config-next 16 — native flat config, drop FlatCompat by @tbcsec in #37

🧹 Other Changes

  • chore(demo): friendly-field seed showcase + simulator ticket/staff pacing by @tbcsec in #34
  • ci: add a merge-result job that tests against current main by @tbcsec in #45

Full Changelog: v1.0.0...v1.1.0

Flagpost v1.0.0 — Initial public release

Choose a tag to compare

@tbcsec tbcsec released this 25 Jul 14:39

The first public release of Flagpost — a modern, open-source CTF competition management platform. Everything below is built, wired, and shipping.

🎯 Run a competition

  • Competitions in individual or team mode — with visibility control, scheduling, pause, archive, and one-click cloning.
  • Teams with invite codes, optional captain approval, size caps, and profiles.
  • Challenges with rich descriptions, categories, per-competition tag & difficulty vocabularies, hints, scheduled/waved release, and prerequisite unlock chains.
  • Flag types: static, regex, multiple-choice (with a guess cap), and dynamic decay scoring.
  • Bulk challenge import/export in ctfcli YAML format.

🏆 Scoreboard & scoring

  • Live scoreboard over WebSocket, with first-blood markers and per-challenge solver lists.
  • Scoreboard freeze, brackets / divisions, a public / spectator board, and a CTFtime feed.

⚡ Realtime & collaboration

  • Live announcements, an in-app notification center with per-user preferences, and presence ("who's viewing this").
  • Collaborative CRDT notes — a team scratchpad per challenge, and staff notes on tickets.

🎫 Support, feedback & analytics

  • Support tickets with staff assignment, internal notes, and a live queue.
  • Surveys and post-solve challenge ratings.
  • Challenge & team analytics.

🤖 Automation

  • An event-driven automation engine with a visual rule builder (When → If → Then).
  • Actions including notifications, announcements, point-bearing awards, hint release, challenge unlock, score adjustment, scoreboard freeze, and egress-hardened webhooks & email.

🛠️ Operate & administer

  • Role-based access control with a custom role editor.
  • A customizable operational dashboard (drag-and-drop widgets).
  • Site theming + custom branding (palettes, accent, org logo), user administration, and full platform export / import backups.
  • First-run setup wizard — no default admin, no hard-coded credentials.

🚀 Deploy

  • A single-origin Docker production stack (docker compose up), plus a documented demo mode.

🔒 Security

Hardened for public use: ReDoS-contained flag matching, a per-install JWT secret, SSRF-hardened webhook egress, CSP + security headers, argon2 password hashing, and stateful refresh sessions. Report vulnerabilities via SECURITY.md — never a public issue.


License: GNU AGPL-3.0 · Docs: README and docs/ · Contributing: CONTRIBUTING.md