DotFlag is an open-source Capture The Flag (CTF) platform built with React + TypeScript on the frontend and .NET 10 + PostgreSQL on the backend. It provides a complete environment for hosting cybersecurity competitions, including real-time scoreboards, virtual container support, and a full admin panel.
- About
- Features
- Tech Stack
- Architecture & Data Model
- Use Case Diagram
- UML Diagrams
- Platform Screenshots
- Getting Started
- License
DotFlag is designed to be a self-hosted, extensible CTF platform suitable for university-level competitions and cybersecurity training. It follows Clean Architecture principles to keep the codebase decoupled, testable, and maintainable.
| Feature | Description |
|---|---|
| Challenges List | Browse, filter, and access challenges across multiple categories (Web, Pwn, Crypto, Reverse Engineering, etc.) |
| Challenge Detail | Dedicated page per challenge with a flag submission field and instant feedback |
| Admin Panel | Full control over challenge creation, user management, and activity logs |
| Leaderboard | Real-time scoreboard ranked by points and submission time |
| Virtual Containers | Integrated support for spawning isolated environments per challenge |
| User Profile | Detailed history of solved challenges, points earned, and performance statistics |
| Team Chat (in progress) | Collaboration tools for team-based competition strategy |
| Technology | Role |
|---|---|
| React 18 | UI framework |
| TypeScript | Type-safe development |
| SWC | Fast compilation |
| Vite | Build tool and dev server |
| Technology | Role |
|---|---|
| .NET 10 | Web API framework (ASP.NET Core) |
| Entity Framework Core | Data access and migrations |
| PostgreSQL | Primary database |
| Session-based Auth | Stateful authentication without JWT tokens |
The project follows Clean Architecture to ensure separation of concerns across layers: API, Application, Domain, and Infrastructure.
The system is built around three core entities:
| Field | Type | Description |
|---|---|---|
| Id | int / guid | Primary key |
| Username | string | Display name |
| string | Login email | |
| PasswordHash | string | Hashed password |
| Role | enum | Admin or User |
| CurrentPoints | int | Accumulated score |
| Field | Type | Description |
|---|---|---|
| Id | int | Primary key |
| Title | string | Challenge name |
| Description | string | Problem statement |
| Points | int | Score value |
| Category | string / enum | e.g. Web, Crypto, Pwn |
| Flag | string | Correct answer (hidden from users) |
| IsActive | bool | Whether the challenge is visible |
| Field | Type | Description |
|---|---|---|
| Id | int | Primary key |
| UserId | int | Reference to User |
| ChallengeId | int | Reference to Challenge |
| SubmittedFlag | string | The flag the user submitted |
| IsCorrect | bool | Whether the submission was correct |
| Timestamp | datetime | Time of submission (used for tiebreaking) |
The core relationship: one User can have many Submissions, and one Challenge can have many Submissions (1 — (N) — 1).
The diagram below illustrates the three actor types and their allowed interactions with the platform.
| Actor | Capabilities |
|---|---|
| Guest | View the landing page, public scoreboard; register or log in |
| User | Browse and filter challenges; submit flags with instant verification; view own profile and statistics |
| Admin | Create, edit, and delete challenges; manage users (ban, change roles); view activity logs (who submitted what flag, when, and from where) |
| Page | Preview |
|---|---|
| Home Page | ![]() |
| Dashboard | ![]() |
| About | ![]() |
| Challenges List | ![]() |
| Challenge Overview | ![]() |
| Leaderboard | ![]() |
| User Profile | ![]() |
| Team | ![]() |
| Admin — Challenges | ![]() |
| Admin — Users | ![]() |
| Admin — Docker | ![]() |
- Node.js 20+
- .NET 10 SDK
- PostgreSQL instance
git clone https://github.com/IvanGazul/DotFlag.git
cd DotFlag/frontend
npm install
npm run devcd DotFlag/backendUpdate the connection string in appsettings.json to point to your PostgreSQL instance:
"ConnectionStrings": {
"Default": "Host=localhost;Database=dotflag;Username=postgres;Password=yourpassword"
}Apply migrations and run:
dotnet ef database update
dotnet runThis project is licensed under the MIT License.











