# The Secure Code Review Challenge — Solution #3: Dice (When Input Sanitization Is Not Enough)

**URL:** <https://threatmodelingconnect.discourse.group/t/the-secure-code-review-challenge-solution-3-dice-when-input-sanitization-is-not-enough/1269>\
**Category:** General\
**Created:** [August 21, 2026, 10:31am UTC](https://threatmodelingconnect.discourse.group/t/the-secure-code-review-challenge-solution-3-dice-when-input-sanitization-is-not-enough/1269 "2026-08-21T10:31:09Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mohamed\_AboElKheir](https://sea2.discourse-cdn.com/flex002/user_avatar/threatmodelingconnect.discourse.group/mohamed_aboelkheir/32/179_2.png) [@Mohamed\_AboElKheir](https://threatmodelingconnect.discourse.group/u/Mohamed_AboElKheir)\
**Post date:** [August 21, 2026, 10:31am UTC](https://threatmodelingconnect.discourse.group/t/the-secure-code-review-challenge-solution-3-dice-when-input-sanitization-is-not-enough/1269/1 "2026-08-21T10:31:09Z")

</div>

📢 The solution to Secure Code Review Challenge #3: Dice is live!

This one’s a reminder that individually “correct” security controls can still combine into a vulnerability. The app sanitizes user input with DOMPurify — a real, well-regarded XSS sanitizer — and it works exactly as advertised. Strip a `<script>` tag? Gone. Strip an `<img onerror>` tag? Gone.

And it still wasn’t enough.

The bug wasn’t in the sanitizer. It was in the order of operations. A Unicode normalization step ran _after_ sanitization instead of before — so fullwidth lookalike characters (＜ ＞) sailed through DOMPurify as harmless “text,” then got silently rewritten into real `<` `>` characters by the normalizer, resurrecting a live HTML tag downstream. One crafted link, zero clicks needed beyond opening it.

🎥 Watch the full walkthrough: [https://youtu.be/Wv1kIrZVLbI](https://youtu.be/Wv1kIrZVLbI)  
📄 Read the write-up: [the-secure-code-review-challenge/solutions/003-dice/SOLUTION.md at main · mohamed-osama-aboelkheir/the-secure-code-review-challenge · GitHub](https://github.com/mohamed-osama-aboelkheir/the-secure-code-review-challenge/blob/main/solutions/003-dice/SOLUTION.md)  
🧩 Try Challenge #3 yourself first: [the-secure-code-review-challenge/challenges/003-dice at main · mohamed-osama-aboelkheir/the-secure-code-review-challenge · GitHub](https://github.com/mohamed-osama-aboelkheir/the-secure-code-review-challenge/tree/main/challenges/003-dice)

Two things before you dive in:  
🔹 Challenge #4 is already live in the repo: [the-secure-code-review-challenge/challenges/004-file-converter at main · mohamed-osama-aboelkheir/the-secure-code-review-challenge · GitHub](https://github.com/mohamed-osama-aboelkheir/the-secure-code-review-challenge/tree/main/challenges/004-file-converter)  
🔹 Watch → Custom → Releases on the repo to get notified the moment new challenges/solutions drop, instead of checking back manually: [Releases · mohamed-osama-aboelkheir/the-secure-code-review-challenge · GitHub](https://github.com/mohamed-osama-aboelkheir/the-secure-code-review-challenge/releases)
