Skip to content

v1.8.0 — Programming challenges & a code judge

Latest

Choose a tag to compare

@tbcsec tbcsec released this 18 Oct 11:11
· 19 commits to main since this release
cc71115

Flagpost v1.8.0 — programming challenges with a built-in code judge, and a security release that closes every open advisory. All deployments should upgrade. Read the upgrade notes first: database migrations run automatically on start, and a few operator steps apply to specific setups.

💻 Programming challenges — a code judge (#446, ADR-0042)

Flagpost can now run programming problems: competitors submit source code, and the judge runs it against hidden test cases and returns a verdict. It is an optional judge module that ships inert, so nothing runs until an operator enables it.

  • Turning it on takes one overlay and one settings page. Start the stack with docker compose -f docker-compose.yml -f docker-compose.judge.yml up -d, then go to Admin → Site settings → Code judge. The page detects the endpoint; pick languages and enable.
    • Submissions run in containers with no network, every capability dropped, and CPU, memory and process limits.
    • The backend reaches Docker only through a socket proxy that refuses exec, volumes and builds.
    • Judging runs on its own worker loop, not on request handlers.
  • For competitors, each programming problem has its own page: the statement and examples, then upload a file or write code in the browser editor.
    • Run examples tries the code without scoring it, and Submit sends it for judging.
    • The verdict arrives live: queue position, then judging, then the result with a one-line explanation.
    • A failing example shows the expected and actual output. A failing hidden test is identified only by its number.
  • For organisers:
    • Authoring: example and hidden test cases, time and memory limits, the languages allowed, the comparison mode and an optional ignore-letter-case check.
    • A reference-solution check runs a known-good solution against every test before competitors do.
    • The Judging page shows the queue and every judging. Staff can rejudge one submission or a whole problem, and override a verdict with a reason. Points always follow the latest verdict.
    • Clarifications: competitors ask from the problem page, and judges answer privately or deliberately send the answer to everyone. A clarification can be withdrawn and stays marked as withdrawn. Judges can also post a clarification without a question, and flag challenges list theirs in the challenge dialog.
    • Problem packages: problems import and export in the open ICPC/Kattis package format. Imports arrive as drafts with a checklist; unsupported features are refused with the reason.
  • Nine languages out of the box: Python 3, PyPy 3, C, C++, Java, Go, Rust, C# and JavaScript. Time multipliers are tiered by measured speed.
  • Scoring is points-first. A programming problem scores like any other challenge, static or dynamic. An ICPC-style ranking mode is planned for a later milestone.
  • Competitors can now download challenge files from the problem page and the challenge dialog.

🔒 Security

This release fixes every open private advisory: the remaining cases of nine reported in the 2026-09-04 review, whose first fixes shipped in v1.7.0, and three found in October. Each advisory, published with this release, gives the details and any workaround.

Advisory Severity Issue
GHSA-mwhq-j3jg-p339 High Delegated user, role or mail-settings management can take over or demote Administrator accounts
GHSA-3r5x-64c8-9q4m Medium Backup access lets a site-settings delegate export every competition's content, flags and invite codes
GHSA-vv68-w7qp-6cpf Medium Authentication hardening: password guessing, login lockout, account enumeration and refresh-token reuse
GHSA-x8v4-p7x5-v6c8 Medium Automation rules: authorization gaps in backup import, the rule list and personal rules
GHSA-r7rp-46pp-x55q Medium Webhook actions allow DNS-rebinding SSRF and memory exhaustion through unbounded responses
GHSA-wvjv-56qv-9v42 Medium Challenge and content-pack import: decompression bombs, YAML expansion and path traversal in exports
GHSA-vgrr-2jpc-mmc5 Medium Challenge instancing: peer reachability, Kubernetes DNS egress to any host, and resource-limit bypass
GHSA-42m4-hhxj-7w3m Medium SSO sign-in: SAML login CSRF and account pre-hijacking through unverified email linking
GHSA-352q-g5xh-3299 Medium CSV formula injection in organiser exports of registration answers, survey responses and submissions
GHSA-q472-m9qw-8gq4 Low Any site-wide delegate role sees, and can join, every private competition
GHSA-r7j2-4hqc-jj7p Low Live standings leak during a scoreboard freeze, and WebSocket rooms skip start and visibility gates
GHSA-4wrj-x53h-hx62 Low Unbounded ticket storage, oversized collaborative-note frames and unvalidated backup restores

Two more advisories from the same September review were fully fixed in v1.7.0 and are published alongside: GHSA-382m-7xrp-wjq8 (self-built backend images can contain the JWT signing secret, encryption key and dev databases) and GHSA-4mmf-rh9c-g428 (any user can join a private competition without its invite code by creating a team, and read its roster).

⚠️ Upgrade notes

  • Back up, then upgrade. Nine database migrations (the judge's tables, and an email column on verification and reset tokens) run automatically when the backend starts.

  • Outstanding email-verification and password-reset links stop working. Links are now bound to the address they were sent to, and links issued before the upgrade carry none. Users request a new one.

  • SAML with an identity provider on a different site needs HTTPS. SAML now uses its own SameSite=None; Secure state cookie so the provider's cross-site POST is accepted; browsers only send that cookie over HTTPS.

  • Kubernetes challenge instances: re-apply k8s/instances-rbac.yaml. The namespace's default-deny egress baseline now allows DNS to the cluster DNS pods only. Test connection reports a missing or outdated baseline. Clusters whose resolver isn't kube-dns in kube-system add a scoped DNS policy (see docs/CHALLENGE_INSTANCES.md).

  • If you launch uvicorn yourself (for example a custom Fargate task) instead of using the shipped images or compose files, add --ws-max-size 2097152. The shipped images already set it.

  • Delegated roles:

    • A site-wide role holding only manage site settings can no longer change the outgoing mail server, or export or import user accounts; those need the full Administrator permission set. The Backup panel offers only the sections whose content the role may see.
    • A delegate can no longer edit, ban, delete or demote an account that holds permissions the delegate lacks.
    • An email address set by a delegate, rather than an Administrator, stays unverified until its owner confirms it.
    • A custom site-wide role with only global-scope permissions no longer lists private competitions it isn't a member of.

    Installs that use only the built-in roles see none of these changes.

  • Challenge instance resource limits must be finite, with whole numbers for memory and process counts, and are floored at 0.01 CPU, 16 MiB and 16 processes. Backup import and both provisioners bring older stored values into these bounds.

  • Zip archives (ctfcli challenge bundles, content packs, problem packages) must use standard deflate compression or none; bzip2 and LZMA members are refused.

  • Marketplace registry mirrors must serve responses uncompressed or with a single gzip/deflate layer; other content encodings are refused.

  • Competitor ticket replies are rate-limited per user, and a collaborative note too large to sync shows a notice instead of silently failing.

✨ Also included

  • The Admin section follows the grant (#480): a colleague given a narrow site-wide role (the event log, auth providers, pages, the marketplace, API-token oversight) now reaches exactly the Admin pages that role covers, and each page offers only the actions they hold.
  • User guides rewritten for v1.8.0 (#479): the Competitor, Judge and Admin guides cover everything since v1.4, including the code judge, and are bundled in the image.

Full history: the in-app /changelog and the v1.8.0 milestone. Source builds now report 1.8.0-src; pull the pinned images from GHCR by tag.

Full changelog: v1.7.1...v1.8.0