Skip to content

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

Choose a tag to compare

@tbcsec tbcsec released this 01 Aug 22:24
· 42 commits to main since this release

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 #124
  • Fix: a docker source build reported "dev", not its version by @tbcsec in #125
  • Put the Site settings tab in the URL (#126) by @tbcsec in #127
  • docs: full currency sweep — the docs were three releases behind by @tbcsec in #128
  • fix(sso): OIDC JIT provisioning granted Participant on every competition by @tbcsec in #129
  • fix(config): refuse to boot on MinIO's default credentials when reachable by @tbcsec in #130
  • fix(security): throttle credential endpoints, close SSRF gap, Secure refresh cookie by @tbcsec in #131

New Contributors

Full Changelog: v1.1.1...v1.2.0