keyboard_arrow_up

title: Welcome in our Harem
date: Apr 20, 2026
tags: hackin harem articles


Harem — the CTF platform we ended up coding ourselves

harem logo

TL;DR

Harem is a full-featured CTF platform we've been building since late 2023. Infra as code, per-team dedicated containers, native anti-cheat, flag per-user, real-time leaderboard, badges, shop, social engineering, gamification. It powered our Hack'In 2025 and 2026 editions and is used in training and corporate events. Here's what it does, why we built it, and what the stakes are behind it.


Why build yet another CTF platform?

Running a CTF is three jobs in one: building challs, setting up the infra, managing the community. Existing platforms cover the first, fake it on the second, and completely ignore the third.

CTFd is the de-facto standard. It's solid, but half the features we want sit behind the enterprise plan: anti-cheat, dedicated containers, per-user flags. And everything is configured through the UI, so you click, you forget what you did, you redo it. For a CTF we run every year, it's unmanageable. As soon as you want to make it more "automated", you end up piling up plugins.

CTFCafé is nicer to use but wasn't designed for our needs. We forked it, slapped Swarm on top, and it held up for one extra hour. Every year we ended up with a platform KO'd at 2 or 3 AM in front of 150 participants.

At some point you have to accept that the tool you want doesn't exist. We started coding Harem late 2023 / early 2024 with three requirements on the back of a napkin:

requirements.txt:
- as code
- private resource
- easy to manage

One year later we decided to use it for our event, a year and a half later we pushed it to its limits while completely wrecking a CTF, and two years later we finally have a stable version, almost ready for open source.


What Harem does — technical advantages

1. Infra as code, end to end

On Harem, each team gets its own GCP VM. It's provisioned via Terraform when the team is created, attached to its owner, and cleanly destroyed at the end of the event. The whole GCP topology (network, firewall, instance, labels, SSH keys) is described as code, versioned alongside the rest of the project.

Three wins:

We also wrote our own CLI (haremctl) to automate everything: haremctl deploy, haremctl update --set KEY=VALUE, haremctl destroy. Same DX as calling docker compose up, except behind it there are 30 VMs.

2. Challenges as code

Each chall is a folder with its docker-compose.yml, its markdown description, its flags, its hints, its categories, its points. No UI fields to fill in. Want to add a chall? Push to the repo, scrape, done.

The platform natively handles:

On CTFd, most of these features are paid or require ctfcli. Here it's the default behavior.

3. Native anti-cheat and autoban

Three detections running continuously:

Alerts surface on a real-time admin dashboard with total / flag sharing / suspicious / unauthorized per category. From there, ban an IP with one click, block a chall for a specific team, revoke a solve.

On CTFd, detection requires the enterprise plan, and bans are manual.

On top of that we can detect a team connecting to another team's challenge and ban accordingly.

4. Real-time leaderboard

WebSocket via Socket.io, no polling. When a team flags, the graph updates on every open page at once. Participants can leave the leaderboard open on a second screen while they work, watching the race live.

The backend sits behind a Redis cache with targeted invalidation — no full rebuild on every solve. At Hack'In 2026 we had ~130 concurrent active users, zero slowdown.

The biggest event we ran gathered 1,500 people and that's where we saw the limits — we rebuilt the whole architecture from scratch at the end of 2025.

5. Gamification — the badge system

Beyond points, Harem awards badges computed dynamically:

Badges are admin-reconfigurable (thresholds, activation, cache TTL). Participant feedback on this system has been unanimously positive, and honestly it's the feature everyone prefers.

We hand out physical badges during the competition and it gives extra goals to those not chasing the top 3.

6. Physical challenges (social engineering)

Harem natively handles non-container challs: social engineering challs, physical challs. Each team has a calendar where they can book slots with the organizers, and the flag is manually validated by an admin. No need to hack around the platform for this.

7. Shop and internal economy

Each team has a points balance. It can:

The shop is also defined as code on the admin side, with fixedPrice or percentageRate (% of the chall's points).

8. Smart image pre-pull

One of the things that kills classic CTF platforms: cold start. A user clicks "start container", Docker pulls the image (several hundred MB), the container boots up, the chall is available 45 seconds later.

On Harem, as soon as a VM is provisioned we can pre-pull all chall images from the admin UI. When the event kicks off and a user clicks "start", the container is up in 2-3 seconds because the image is already local.

9. Data management

Harem is designed to never store "enriched" data. That has ENORMOUS advantages but one absolutely huge drawback: a heavy resource consumption.

For example we never store the leaderboard in the database. Nor how many points a team has. Nor how many challenges a team has solved. We just store the challenges solved by users.

Then if we want the team's point total, we have to fetch the challenges solved by each user, go check the points for each, add them up with the other challenges, and compute with the other members of the team.

It's very heavy, but the upside is that at any moment we can change the points of a challenge mid-competition (or any other piece of data) without wrecking the database. We update our .yaml, rescrape the challenges and all the data is up to date.

Except that above 1000 users it becomes way too greedy for the platform. So here's how we handle our data:

  1. MongoDB => source of truth, data is RAW and never enriched
  2. Redis => mostly "event-driven" with no TTL, holds the enriched data (leaderboard, team members, badges earned...)

With a hit rate above 90% we cut Harem's resource consumption, while keeping the flexibility of an as-code platform.

Our routes just update the cache without invalidating it, and we have fallbacks that enrich it. In case of data inconsistency, the admin UI exposes a cache management panel that invalidates everything and rebuilds from MongoDB, which is the source of truth.


What Harem does — organizational advantages

Tech is one thing, but a CTF is first and foremost an event to run. Harem was designed so that 3 admins can handle 100+ live participants without drowning.

Challenge ratings

Each participant can rate challenges right after solving them. It gives us feedback on every chall across three factors:

On our side this system lets us massively improve our challenges year after year.

Integrated support tickets

Participants open a ticket from inside the platform, no need to cross-reference Discord/Slack/email. Admins see Total / New / Open / Closed, filter by team / reference, reply in markdown with attachments.

Activity monitor

A dashboard listing:

When a user crosses the threshold, they flip to "suspicious" and float to the top of the list. If it's a cheater, IP ban in one click. If it's a fuzzer, you patch the chall to block fuzzing rather than ban them.

Docker containers management

Global list of every container running on the infra. Per container: team, chall, port, deployed at. Actions: clean unassigned (orphans from a destroyed team), delete all (after the event), kill a specific container.

Async VM management

DELETE /api/admin/vm/:vmId is asynchronous. It returns 202 immediately and runs the terraform destroy in the background. VMs stuck in deleting > 10 min are flipped to error by a recovery service at boot. Sounds trivial but if you've never managed a pool of 30 VMs where a few reboot badly at the end of an event, you don't know how life-saving it is.

Demo seeder

A single command that fills the DB with fake users, teams and solves to test features on a realistic environment. Useful to onboard speakers, test a release, demo the product to a sponsor without wiping the live CTF.

Admin stats

A full dashboard for organizers:

That's what let us hit a 4.53/5 average rating on the 2025 edition: we know which challs feel "guessy", which ones feel "incomprehensible", and we adjust before the next edition.


What Harem lets you do that CTFd doesn't

Beyond the comparable features, there are three use cases that no public platform really covers:

1. Scaling The platform automatically provisions VMs on team creation, and can spread teams across VMs. We don't really have infra to manage anymore — it's defined in terraforms and all you need is a credit card.

2. As code. Frankly, ultra pleasant. Everything is as code and it was designed to be. You just need to take the time to generate the GCP access, then you can redeploy the platform instantly. It's ultra flexible on challenge management, and since no enriched data is stored in the DB you can just push an update to your challenge repo and the change is live in the competition instantly.

3. Flexibility. The other win for us: we know the platform by heart. We're super confident adding features and generally doing whatever we want. We have tons of ideas and often you can't test them all with CTFd — you depend on the plugin system. And we don't want to maintain a Fork. Sure, with CTFd you basically never have problems because the platform is super mature. But we'd much rather have our unstable flexibility than a stability that locks us in. Worst case we fix and redeploy in prod, we're used to it 🤡.


The stakes

All of that is the rosy side. Here's what's less comfortable.

Cloud quotas

The first time we tried to spawn 30 VMs at once on GCP, here's what we took in the face, in order:

  1. After the 9th VM → out of quota for public IPs
  2. After resizing → out of CPU quota
  3. After resizing → out of instance quota

Every quota request on GCP is a ticket you have to justify, sometimes with several days of delay. We learned to pre-request quotas months ahead of each event.

Financial sustainability

Each event is 500-1500€ of GCP out of our own pockets. And we don't have great visibility on it. We just run the numbers with GCP's tooling.

So we pay per usage, a bit blind, but we don't have to buy 10K€ of servers to deploy VMs etc. We always have working machines, 0 hardware to manage, we pay the price of freedom and flexibility.

For context, the first three editions of Hack'In were full on-prem infra that we hosted ourselves. Never again never again never again please.

Instability

We have 500 ideas, we spend our time testing them, always new options and we don't have time for stability. That's why we haven't opened the platform yet. When something doesn't work, we fix in prod, we're used to it by now.

There's adrenaline, it's exciting but overall we're pretty confident because the way we handle data lets us make mistakes. Push the right fix and the competition is back on without starting from zero.

Example: for our 5th edition we discovered during the competition that our bounty system was unstable (we had devved it the week before). Basically, you could exceed the cap on teams eligible for a bounty on a given challenge.

Except we don't have a bountyAmount field in our DB to know how much a team has earned in bounties.

Our flow: Look up the challenges solved by a user -> Does this challenge have bounties? -> how many bounties are left (bug) -> is our user eligible for the bounty? -> Add it to the computed bounties -> store in our cache bounty:<team-id>:amount the total.

So when we caught the bug we:

And the competition could resume. We didn't have to go remove data in the DB and risk creating inconsistencies.

With CTFd we'd never have been this confident pushing that kind of fix mid-competition. Except that with CTFd you don't need to push that kind of fix because it's mature. But CTFd doesn't provide a bounty system and we wanted one. So we would've had to build a plugin, knowing we'd be 0 flexible if there's a bug.

So once again, we prefer our unstable flexibility over a stability that locks us in — but that's an organizational choice.


Hack'In 2026 retex

What is your overall satisfaction level with the CTF platform?: 4.90/5.

Participant feedback:

"Frankly, literally 0 technical issues, pretty incredible (miraculous?). Really pleasant to have a platform that works and is overall super performant (containers start/stop super fast, fluid interface that updates with the right info)."

"The CTF platform is really on point, two or three tiny UI/UX inconsistencies but we're talking real nitpicks. The badge concept is really incredible, so so good, nothing else to say."

"the badge system and the badge shop is masterclass. I even think it should be developed further. (we know perfectly well we're not fighting for the podium, we don't have the level and we just want to have fun, there's really something to build at that level)."


Access

If you're a CTF event organizer you can join us here: https://discord.gg/dSftTaTyBH

Because of its instability we haven't made the repo public yet, but we're happy to give access if you need it for your next events! Just ping me :)

Why Harem?

The answer to the question we get asked most:

The project is called Harem. Yes, we know. No, we don't not care.

A harem is a forbidden place, a place forbidden to men. With this "Harem" CTF platform, you too end up virtually in a place where you can do things that are normally forbidden. A controlled environment where you train to do things that are illegal anywhere else. Breaking into systems, exploiting vulnerabilities, bypassing security — all of it in a legal framework.

So no, it's not what you think. But we're not going to pretend the name didn't make me laugh.