Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
IT NachrichtenDNA-Computer rechnet ohne Strom und bricht Tempo-Rekord(23.09.2026 um 13:39 Uhr)
IT NachrichtenApple arbeitet an Fitnesstracker ohne Display(23.09.2026 um 12:37 Uhr)
IT NachrichtenDiese Serien scheiterten mit Staffel 2(23.09.2026 um 13:20 Uhr)
IT NachrichtenDNA-Computer rechnet ohne Strom und bricht Tempo-Rekord(23.09.2026 um 13:39 Uhr)
IT NachrichtenApple arbeitet an Fitnesstracker ohne Display(23.09.2026 um 12:37 Uhr)
IT NachrichtenDiese Serien scheiterten mit Staffel 2(23.09.2026 um 13:20 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Week 6 Quiz Audit XSS Vulnerabilities

📚 Part of Week 6 in the SecEng-Exercises curriculum - a free, open-source path to becoming a Security Engineer. Star the repo to follow along with weekly challenges! The $5 Million XSS Disaster It was 3 AM when the security te…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

📚 Part of Week 6 in the SecEng-Exercises curriculum - a free, open-source path to becoming a Security Engineer. Star the repo to follow along with weekly challenges!







The $5 Million XSS Disaster



It was 3 AM when the security team at TechFinance Corporation received the alert. Their customer portal—processing millions of dollars in transactions daily—had been compromised. The attack vector? A simple Cross-Site Scripting (XSS) vulnerability in their search functionality.



The attacker had crafted a malicious URL containing JavaScript that stole session cookies. They shared it on social media disguised as a "special promotion." Within hours, thousands of customers clicked the link. The malicious script silently harvested authentication tokens, granting the attacker access to customer accounts.



By morning, the damage was catastrophic:




  • 15,000+ customer accounts compromised

  • $5.2 million in unauthorized transfers


  • Complete database exfiltration including social security numbers


  • Stock price plummeted 40% after disclosure


  • Class action lawsuit filed within 72 hours



The company's Chief Security Officer resigned. The engineering team worked 72-hour shifts to contain the breach. Regulatory fines exceeded $12 million. All because of a single XSS vulnerability that should have been caught in code review.



Don't let this happen to your application.










🎓 Learning Security Engineering?



This challenge is from my free, open-source Security Engineering curriculum with:




  • ✅ LeetCode-style exercises with 60+ test cases

  • ✅ Real CVEs and production-incident inspired scenarios

  • ✅ Complete solutions with best practices

  • ✅ New challenges added weekly



Star SecEng-Exercises on GitHub - Join developers mastering AppSec fundamentals!










🎯 Part of the SecEng-Exercises Collection



This XSS challenge is Week 6 of my comprehensive Security Engineering curriculum. I'm building a public collection of LeetCode-style security exercises with:




  • 60+ test cases per exercise for thorough validation

  • Real-world vulnerability patterns from production systems

  • Hands-on pentesting practice against intentionally vulnerable code

  • Complete solutions with security best practices



Star the repo on GitHub to follow along as I add new exercises weekly covering AppSec, cryptography, API security, and more.




💡 Why star the repo? You'll get notified when I publish new challenges covering SQL injection, authentication bypasses, cryptographic vulnerabilities, and advanced API attacks. All exercises include comprehensive test suites and are production-incident inspired.







📋 What You'll Learn in This Post





  1. Real XSS attack scenario and its $5M+ impact


  2. Three vulnerable code challenges to test your skills


  3. Complete vulnerability analysis with fix implementations


  4. Prevention patterns used by security teams at top tech companies



Estimated completion time: 30-45 minutes | Difficulty: Intermediate | Prerequisites: Basic Python, HTML/JavaScript









Your Challenge: Find the XSS Vulnerabilities



Below are three real-world code snippets, each containing multiple XSS vulnerabilities. Your task is to:





  1. Identify all security vulnerabilities in each snippet


  2. Understand how an attacker could exploit them


  3. Fix the code to prevent XSS attacks



These exercises are based on patterns from production systems and real security incidents. Study each carefully—the vulnerabilities range from obvious to subtle.



Sources for these exercises:





  • Full Stack Python Security by Dennis Byrne, Chapter 14, pp. 208-2261


  • API Security in Action by Neil Madden, Chapter 2, pp. 54-552


  • Secure by Design by Johnsson et al., Chapter 9, pp. 247-2493


  • Hacking APIs by Corey Ball4




📖 Following the curriculum? I'm documenting my journey through these books in the SecEng-Exercises repository, creating exercises for each chapter. Week 7 covers Full Stack Python Security Chapter 15 (CSRF) and Hacking APIs Chapter 3 (API Authentication Bypasses). Star the repo for weekly updates!










Vulnerable Code Snippet #1: Flask Search Application






from flask import Flask, request

app = Flask(__name__)

@app.route('/search')
def search():
"""Search endpoint - handles user queries"""
query = request.args.get('q', '')

# Simulate database search
results = []
if query:
query_lower = query.lower()
if 'laptop' in query_lower:
results = [
{'name': 'Gaming Laptop Pro', 'price': 1299.99, 'stock': 12},
{'name': 'Business Laptop Elite', 'price': 899.99, 'stock': 8},
]

# Generate HTML response
html = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset=
"UTF-8">
<title>Search Results</title>
</head>
<body>
<h1>Search Results for: <span>
{query}</span></h1>
<div class=
"results">
"""

if results:
for product in results:
html += f"""
<div class=
"product">
<h3>
{product['name']}</h3>
<div class=
"price">${product['price']}</div>
<div class=
"stock">In stock: {product['stock']} units</div>
</div>
"""
else:
html += f"""
<div class=
"no-results">
<h2>No Results Found</h2>
<p>Your search for
'<strong>{query}</strong>' did not match any products.</p>
</div>
"""

html += """
</div>
</body>
</html>
"""

return html

if __name__ == '__main__':
app.run(debug=True, port=5000, host='127.0.0.1')












Vulnerable Code Snippet #2: FastAPI Comment Board






from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
import sqlite3
import html

app = FastAPI()

class Comment(BaseModel):
author: str
content: str

@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
"""Main page with comment form"""
return """
<!DOCTYPE html>
<html>
<head>
<meta charset=
"UTF-8">
<title>Comment Board</title>
</head>
<body>
<h1>Community Comment Board</h1>
<form id=
"commentForm">
<input type=
"text" id="author" placeholder="Your name" required>
<textarea id=
"content" placeholder="Your comment" required></textarea>
<button type=
"submit">Post Comment</button>
</form>
<div id=
"commentsContainer"></div>

<script>
// Load comments when page loads
loadComments();

// Handle form submission
document.getElementById(
'commentForm').addEventListener('submit', async (e) => {
e.preventDefault();

const author = document.getElementById(
'author').value;
const content = document.getElementById(
'content').value;

const response = await fetch(
'/api/comments', {
method:
'POST',
headers: {
'Content-Type': 'application/json'},
body: JSON.stringify({ author, content })
});

if (response.ok) {
document.getElementById(
'author').value = '';
document.getElementById(
'content').value = '';
loadComments();
}
});

// Load and display comments
async function loadComments() {
const response = await fetch(
'/api/comments');
const comments = await response.json();

const container = document.getElementById(
'commentsContainer');
container.innerHTML =
'';

comments.forEach(comment => {
const div = document.createElement(
'div');
div.className =
'comment';

div.innerHTML = `
<div class=
"comment-author">${comment.author}</div>
<div class=
"comment-time">${comment.timestamp}</div>
<div class=
"comment-content">${comment.content}</div>
`;
container.appendChild(div);
});
}
</script>
</body>
</html>
"""

@app.post("/api/comments")
async def create_comment(comment: Comment):
"""Create a new comment"""
conn = sqlite3.connect('comments.db')
cursor = conn.cursor()

# Escape HTML to prevent XSS
author = html.escape(comment.author, quote=True)
content = html.escape(comment.content, quote=True)

# SQL Injection vulnerable query
query = f"INSERT INTO comments (author, content, timestamp) VALUES ('{author}', '{content}', datetime('now'))"
cursor.execute(query)

conn.commit()
conn.close()

return {"status": "success"}

@app.get("/api/comments")
async def get_comments():
"""Get all comments"""
conn = sqlite3.connect('comments.db')
cursor = conn.cursor()

# SQL Injection vulnerable query
query = "SELECT author, content, timestamp FROM comments ORDER BY id DESC"
cursor.execute(query)

comments = []
for row in cursor.fetchall():
comments.append({
"author": row[0],
"content": row[1],
"timestamp": row[2]
})

conn.close()
return comments












Vulnerable Code Snippet #3: Session Management API






from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import sqlite3

app = FastAPI()

@app.post("/auth/register")
async def register(username: str, password: str):
"""Register a new user"""
conn = sqlite3.connect('security_app.db')
cursor = conn.cursor()

# Store user in database
cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)",
(username, password))

user_id = cursor.lastrowid
conn.commit()
conn.close()

return {"user_id": user_id, "username": username}

@app.post("/sessions/create")
async def create_session(user_id: int, metadata: str):
"""Create a new session"""
conn = sqlite3.connect('security_app.db')
cursor = conn.cursor()

import secrets
session_id = secrets.token_urlsafe(32)

# Store raw session ID in database
cursor.execute(
"INSERT INTO sessions (session_id, user_id, metadata) VALUES (?, ?, ?)",
(session_id, user_id, metadata)
)

conn.commit()
conn.close()

return {"session_id": session_id}

@app.get("/", response_class=HTMLResponse)
async def home():
"""Frontend with session management"""
return """
<!DOCTYPE html>
<html>
<head>
<meta charset=
"UTF-8">
<title>Session Manager</title>
</head>
<body>
<h1>Session Management System</h1>

<div id=
"register_section">
<h2>Register</h2>
<input type=
"text" id="register_username" placeholder="Username">
<input type=
"password" id="register_password" placeholder="Password">
<button onclick=
"registerUser()">Register</button>
<div id=
"register_result"></div>
</div>

<div id=
"login_section">
<h2>Login</h2>
<input type=
"text" id="login_username" placeholder="Username">
<input type=
"password" id="login_password" placeholder="Password">
<button onclick=
"loginUser()">Login</button>
<div id=
"login_result"></div>
</div>

<div id=
"profile_section">
<h2>Get Profile</h2>
<input type=
"text" id="profile_user_id" placeholder="User ID">
<button onclick=
"getProfile()">Get Profile</button>
<div id=
"profile_result"></div>
</div>

<script>
async function registerUser() {
const username = document.getElementById(
'register_username').value;
const password = document.getElementById(
'register_password').value;

const response = await fetch(
'/auth/register', {
method:
'POST',
headers: {
'Content-Type': 'application/json'},
body: JSON.stringify({username, password})
});

const data = await response.json();
const result = document.getElementById(
'register_result');

if (response.ok) {
result.innerHTML = `<div class=
"result">✓ Registered! User ID: ${data.user_id}, Username: ${data.username}</div>`;
} else {
result.innerHTML = `<div class=
"result error">✗ ${data.detail}</div>`;
}
}

async function loginUser() {
const username = document.getElementById(
'login_username').value;
const password = document.getElementById(
'login_password').value;

const response = await fetch(
'/auth/login', {
method:
'POST',
headers: {
'Content-Type': 'application/json'},
body: JSON.stringify({username, password})
});

const data = await response.json();
const result = document.getElementById(
'login_result');

if (response.ok) {
result.innerHTML = `<div class=
"result">✓ Login successful! User ID: ${data.user_id}</div>`;
} else {
result.innerHTML = `<div class=
"result error">✗ ${data.message}</div>`;
}
}

async function getProfile() {
const userId = document.getElementById(
'profile_user_id').value;

const response = await fetch(`/auth/profile/${userId}`);
const data = await response.json();
const result = document.getElementById(
'profile_result');

if (response.ok) {
result.innerHTML = `
<div class=
"result">
<h4>Profile Information</h4>
<p><strong>Username:</strong> ${data.username}</p>
<p><strong>Bio:</strong> ${data.bio}</p>
<p><strong>Created:</strong> ${data.created_at}</p>
</div>
`;
} else {
result.innerHTML = `<div class=
"result error">✗ ${data.detail}</div>`;
}
}
</script>
</body>
</html>
"""












🔒 Test Yourself First



Before scrolling to the answers, try identifying the vulnerabilities yourself! Each exercise in the SecEng-Exercises repository includes:





  • Automated test suites with 60+ test cases


  • Vulnerable and fixed versions for comparison

  • Step-by-step exploitation guides

  • Production-ready security patterns



⭐ Star the repo to get the full test suites and run the exploits yourself. The hands-on practice is 10x more valuable than just reading solutions.









Answer Key: Vulnerabilities & Fixes






Exercise 1: Flask Search Application



Identified Vulnerabilities:





  1. Reflected XSS Vulnerability (Critical)





    • Location: Lines where {query} is directly embedded in HTML


    • Impact: Attacker can inject malicious JavaScript via the search parameter


    • Example Attack: ?q=<script>alert(document.cookie)</script>


    • Reference: Full Stack Python Security, Chapter 14, pp. 208-2121




  2. Missing Security Headers




    • No X-XSS-Protection header

    • No X-Content-Type-Options: nosniff header

    • No Content-Security-Policy header


    • Reference: Secure by Design, Chapter 9, pp. 247-2493




  3. Missing Rate Limiting




    • Attacker can overwhelm server with excessive requests

    • No protection against brute-force attacks




  4. Debug Mode Enabled in Production





    • debug=True exposes sensitive stack traces and system information

    • Should always be False in production environments





Fixed Code:




from flask import Flask, request
from flask_talisman import Talisman
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import html

app = Flask(__name__)

# Configure security headers with Talisman
talisman = Talisman(
app,
content_security_policy={
'default-src': ["'self'"]
}
)

# Add rate limiting
limiter = Limiter(
key_func=get_remote_address,
app=app,
default_limits=["100/hour"],
storage_uri="memory://",
)

# Enable security headers
talisman.x_xss_protection = True
talisman.x_content_type_options = True

@app.route('/search')
@limiter.limit("30/minute")
def search():
"""Search endpoint - handles user queries"""
query = request.args.get('q', '')

# ✅ FIX: HTML escape user input to prevent XSS
query_escaped = html.escape(query, quote=True)

# Simulate database search
results = []
if query:
query_lower = query.lower()
if 'laptop' in query_lower:
results = [
{'name': 'Gaming Laptop Pro', 'price': 1299.99, 'stock': 12},
{'name': 'Business Laptop Elite', 'price': 899.99, 'stock': 8},
]

# Generate HTML response with escaped query
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset=
"UTF-8">
<title>Search Results</title>
</head>
<body>
<h1>Search Results for: <span>
{query_escaped}</span></h1>
<div class=
"results">
"""

if results:
for product in results:
html_content += f"""
<div class=
"product">
<h3>
{html.escape(product['name'])}</h3>
<div class=
"price">${product['price']}</div>
<div class=
"stock">In stock: {product['stock']} units</div>
</div>
"""
else:
html_content += f"""
<div class=
"no-results">
<h2>No Results Found</h2>
<p>Your search for
'<strong>{query_escaped}</strong>' did not match any products.</p>
</div>
"""

html_content += """
</div>
</body>
</html>
"""

return html_content

if __name__ == '__main__':
# ✅ FIX: Disable debug mode in production
app.run(debug=False, port=5000, host='127.0.0.1')






Key Security Improvements:




  • Used html.escape() to sanitize all user input1

  • Added Flask-Talisman for Content Security Policy

  • Implemented rate limiting with Flask-Limiter

  • Disabled debug mode

  • Added X-XSS-Protection and X-Content-Type-Options headers




💡 Want the complete test suite? The GitHub repository includes 60+ pytest test cases for this exercise, including edge cases like double-encoded attacks, null byte injection, and DOM clobbering attempts. Star the repo to access all test files!










Exercise 2: FastAPI Comment Board



Identified Vulnerabilities:





  1. Stored/DOM XSS Vulnerability (Critical)





    • Location: Line where div.innerHTML is set with unescaped comment data


    • Impact: Malicious JavaScript stored in database executes when loaded


    • Attack Flow:


      1. Attacker posts comment with XSS payload

      2. Payload stored in database (even though it's HTML-escaped on server)

      3. Server returns escaped HTML entities to client

      4. Client-side JavaScript inserts into DOM via innerHTML

      5. Browser unescapes HTML entities and executes script








    • Reference: Full Stack Python Security, Chapter 14, pp. 213-2201








  2. SQL Injection Vulnerability (Critical)





    • Location: String interpolation in SQL queries

    • Despite HTML escaping, the query uses f-string formatting which is vulnerable


    • Reference: API Security in Action, Chapter 2, pp. 54-552








  3. Missing Rate Limiting




    • No protection against comment spam or DoS attacks








  4. Inline Scripts Without CSP Nonces










Fixed Code:




from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from slowapi import Limiter
from slowapi.util import get_remote_address
import sqlite3
import html

app = FastAPI()

# Add rate limiting
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

class Comment(BaseModel):
author: str
content: str

@app.get("/", response_class=HTMLResponse)
@limiter.limit("10/minute")
async def home(request: Request):
"""Main page with comment form"""
return """
<!DOCTYPE html>
<html>
<head>
<meta charset=
"UTF-8">
<meta http-equiv=
"Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'">
<title>Comment Board</title>
</head>
<body>
<h1>Community Comment Board</h1>
<form id=
"commentForm">
<input type=
"text" id="author" placeholder="Your name" required>
<textarea id=
"content" placeholder="Your comment" required></textarea>
<button type=
"submit">Post Comment</button>
</form>
<div id=
"commentsContainer"></div>

<script>
loadComments();

document.getElementById(
'commentForm').addEventListener('submit', async (e) => {
e.preventDefault();

const author = document.getElementById(
'author').value;
const content = document.getElementById(
'content').value;

const response = await fetch(
'/api/comments', {
method:
'POST',
headers: {
'Content-Type': 'application/json'},
body: JSON.stringify({ author, content })
});

if (response.ok) {
document.getElementById(
'author').value = '';
document.getElementById(
'content').value = '';
loadComments();
}
});

// ✅ FIX: Use textContent instead of innerHTML to prevent XSS
async function loadComments() {
const response = await fetch(
'/api/comments');
const comments = await response.json();

const container = document.getElementById(
'commentsContainer');
container.innerHTML =
'';

comments.forEach(comment => {
const div = document.createElement(
'div');
div.className =
'comment';

// Create separate elements and use textContent
const authorDiv = document.createElement(
'div');
authorDiv.className =
'comment-author';
authorDiv.textContent = comment.author; // ✅ Safe: Uses textContent

const timeDiv = document.createElement(
'div');
timeDiv.className =
'comment-time';
timeDiv.textContent = comment.timestamp; // ✅ Safe: Uses textContent

const contentDiv = document.createElement(
'div');
contentDiv.className =
'comment-content';
contentDiv.textContent = comment.content; // ✅ Safe: Uses textContent

div.appendChild(authorDiv);
div.appendChild(timeDiv);
div.appendChild(contentDiv);

container.appendChild(div);
});
}
</script>
</body>
</html>
"""

@app.post("/api/comments")
@limiter.limit("5/minute")
async def create_comment(request: Request, comment: Comment):
"""Create a new comment"""
conn = sqlite3.connect('comments.db')
cursor = conn.cursor()

# ✅ FIX: Use parameterized queries to prevent SQL injection
query = "INSERT INTO comments (author, content, timestamp) VALUES (?, ?, datetime('now'))"
cursor.execute(query, (comment.author, comment.content))

conn.commit()
conn.close()

return {"status": "success"}

@app.get("/api/comments")
@limiter.limit("10/minute")
async def get_comments(request: Request):
"""Get all comments"""
conn = sqlite3.connect('comments.db')
cursor = conn.cursor()

# ✅ FIX: Use parameterized query
query = "SELECT author, content, timestamp FROM comments ORDER BY id DESC"
cursor.execute(query)

comments = []
for row in cursor.fetchall():
comments.append({
"author": row[0],
"content": row[1],
"timestamp": row[2]
})

conn.close()
return comments






Key Security Improvements:





  • Critical: Changed from innerHTML to textContent for DOM manipulation1

  • Used parameterized SQL queries to prevent SQL injection2

  • Added Content-Security-Policy header

  • Implemented rate limiting on all endpoints

  • Removed HTML escaping on server since client now uses textContent (defense in depth still valuable)



Why innerHTML is Dangerous:

Even though the server HTML-escapes the data, when the client retrieves it and uses innerHTML, the browser automatically unescapes HTML entities, converting <script> back to <script>, which then executes. Using textContent prevents this by treating everything as plain text.1




🔥 Pro Tip: Exercise 2 in the SecEng-Exercises repo includes a bonus challenge on CSP nonces and hash-based script whitelisting—an advanced defense technique used by Google and Facebook. Star to unlock!








Exercise 3: Session Management API



Identified Vulnerabilities:





  1. Multiple DOM-Based XSS Vulnerabilities (Critical)





    • Locations: Every use of .innerHTML in JavaScript functions

    • Lines with result.innerHTML = ...${data.user_id}... and similar


    • Impact: API responses containing malicious data execute as JavaScript


    • Reference: Full Stack Python Security, Chapter 14, pp. 220-2261




  2. Session ID Storage Vulnerability (High)





    • Location: create_session() stores raw session ID in database


    • Impact: If database is compromised, all session IDs are exposed


    • Best Practice: Store only hashed session IDs2




  3. Missing Rate Limiting (Medium)




    • No protection against brute-force login attempts

    • No limits on session creation




  4. Password Storage Issue (Critical, implied)




    • Password likely stored in plaintext (not shown hashing in register)

    • Should use bcrypt or similar





Fixed Code:




from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import sqlite3
import secrets
import hashlib

app = FastAPI()

# Add rate limiting (import statements omitted for brevity)

@app.post("/auth/register")
async def register(username: str, password: str):
"""Register a new user"""
conn = sqlite3.connect('security_app.db')
cursor = conn.cursor()

# ✅ FIX: Hash password before storing
import bcrypt
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())

cursor.execute("INSERT INTO users (username, password_hash) VALUES (?, ?)",
(username, password_hash))

user_id = cursor.lastrowid
conn.commit()
conn.close()

return {"user_id": user_id, "username": username}

@app.post("/sessions/create")
async def create_session(user_id: int, metadata: str):
"""Create a new session"""
conn = sqlite3.connect('security_app.db')
cursor = conn.cursor()

session_id = secrets.token_urlsafe(32)

# ✅ FIX: Store hashed session ID, not raw value
session_hash = hashlib.sha256(session_id.encode()).hexdigest()

cursor.execute(
"INSERT INTO sessions (session_hash, user_id, metadata) VALUES (?, ?, ?)",
(session_hash, user_id, metadata)
)

conn.commit()
conn.close()

# Return raw session ID to client (only once)
return {"session_id": session_id}

@app.get("/", response_class=HTMLResponse)
async def home():
"""Frontend with session management"""
return """
<!DOCTYPE html>
<html>
<head>
<meta charset=
"UTF-8">
<meta http-equiv=
"Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'">
<title>Session Manager</title>
</head>
<body>
<h1>Session Management System</h1>

<div id=
"register_section">
<h2>Register</h2>
<input type=
"text" id="register_username" placeholder="Username">
<input type=
"password" id="register_password" placeholder="Password">
<button onclick=
"registerUser()">Register</button>
<div id=
"register_result"></div>
</div>

<div id=
"login_section">
<h2>Login</h2>
<input type=
"text" id="login_username" placeholder="Username">
<input type=
"password" id="login_password" placeholder="Password">
<button onclick=
"loginUser()">Login</button>
<div id=
"login_result"></div>
</div>

<div id=
"profile_section">
<h2>Get Profile</h2>
<input type=
"text" id="profile_user_id" placeholder="User ID">
<button onclick=
"getProfile()">Get Profile</button>
<div id=
"profile_result"></div>
</div>

<script>
// ✅ FIX: Helper function to safely display text
function createTextElement(tag, className, text) {
const element = document.createElement(tag);
element.className = className;
element.textContent = text; // Safe: textContent prevents XSS
return element;
}

async function registerUser() {
const username = document.getElementById(
'register_username').value;
const password = document.getElementById(
'register_password').value;

const response = await fetch(
'/auth/register', {
method:
'POST',
headers: {
'Content-Type': 'application/json'},
body: JSON.stringify({username, password})
});

const data = await response.json();
const result = document.getElementById(
'register_result');
result.innerHTML =
''; // Clear previous content

if (response.ok) {
const div = document.createElement(
'div');
div.className =
'result';
// ✅ FIX: Use textContent instead of innerHTML
div.textContent = `✓ Registered! User ID: ${data.user_id}, Username: ${data.username}`;
result.appendChild(div);
} else {
const div = document.createElement(
'div');
div.className =
'result error';
div.textContent = `✗ ${data.detail}`;
result.appendChild(div);
}
}

async function loginUser() {
const username = document.getElementById(
'login_username').value;
const password = document.getElementById(
'login_password').value;

const response = await fetch(
'/auth/login', {
method:
'POST',
headers: {
'Content-Type': 'application/json'},
body: JSON.stringify({username, password})
});

const data = await response.json();
const result = document.getElementById(
'login_result');
result.innerHTML =
'';

if (response.ok) {
const div = document.createElement(
'div');
div.className =
'result';
// ✅ FIX: Use textContent
div.textContent = `✓ Login successful! User ID: ${data.user_id}`;
result.appendChild(div);
} else {
const div = document.createElement(
'div');
div.className =
'result error';
div.textContent = `✗ ${data.message}`;
result.appendChild(div);
}
}

async function getProfile() {
const userId = document.getElementById(
'profile_user_id').value;

const response = await fetch(`/auth/profile/${userId}`);
const data = await response.json();
const result = document.getElementById(
'profile_result');
result.innerHTML =
'';

if (response.ok) {
// ✅ FIX: Build DOM safely without innerHTML
const div = document.createElement(
'div');
div.className =
'result';

const h4 = document.createElement(
'h4');
h4.textContent =
'Profile Information';
div.appendChild(h4);

const usernamePara = document.createElement(
'p');
const usernameStrong = document.createElement(
'strong');
usernameStrong.textContent =
'Username: ';
usernamePara.appendChild(usernameStrong);
usernamePara.appendChild(document.createTextNode(data.username));
div.appendChild(usernamePara);

const bioPara = document.createElement(
'p');
const bioStrong = document.createElement(
'strong');
bioStrong.textContent =
'Bio: ';
bioPara.appendChild(bioStrong);
bioPara.appendChild(document.createTextNode(data.bio));
div.appendChild(bioPara);

const createdPara = document.createElement(
'p');
const createdStrong = document.createElement(
'strong');
createdStrong.textContent =
'Created: ';
createdPara.appendChild(createdStrong);
createdPara.appendChild(document.createTextNode(data.created_at));
div.appendChild(createdPara);

result.appendChild(div);
} else {
const div = document.createElement(
'div');
div.className =
'result error';
div.textContent = `✗ ${data.detail}`;
result.appendChild(div);
}
}
</script>
</body>
</html>
"""






Key Security Improvements:





  • Replaced ALL innerHTML assignments with safe DOM manipulation1

  • Used textContent to prevent XSS when displaying user data

  • Added password hashing with bcrypt

  • Implemented session ID hashing before database storage2

  • Added Content-Security-Policy header

  • Should add rate limiting (not shown for brevity)



Pattern to Remember:




// ❌ DANGEROUS
element.innerHTML = `<p>${untrustedData}</p>`;

// ✅ SAFE
const p = document.createElement('p');
p.textContent = untrustedData;
element.appendChild(p);












Key Takeaways






The Three Types of XSS





  1. Reflected XSS (Exercise 1): User input immediately reflected in response


  2. Stored XSS (Exercise 2): Malicious payload stored in database


  3. DOM-Based XSS (Exercise 3): Vulnerability in client-side JavaScript






Universal Prevention Rules





  1. Never trust user input - Always assume it's malicious


  2. Escape output - Use html.escape() in Python, textContent in JavaScript


  3. Use parameterized queries - Prevent SQL injection


  4. Implement CSP - Content Security Policy headers


  5. Rate limit everything - Prevent abuse and DoS


  6. Hash sensitive data - Session IDs, passwords, tokens


  7. Disable debug mode - Never run production with debug=True



These exercises are inspired by real vulnerabilities and industry-standard security books. I invest significant time ensuring each exercise is:





  • Technically accurate - Based on actual CVEs and production incidents


  • Properly cited - All patterns sourced from authoritative security literature


  • Interview-relevant - Covers topics asked in Security Engineer interviews at FAANG+ companies



All 48 weeks of exercises available in the SecEng-Exercises repository. Star it to stay updated!






References






  1. Byrne, Dennis. Full Stack Python Security. Manning Publications, 2021. Chapter 14: "Cross-Site Scripting", pp. 208-226.






  1. Madden, Neil. API Security in Action. Manning Publications, 2020. Chapter 2: "Secure API development", pp. 54-55.






  1. Johnsson, Dan, et al. Secure by Design. Manning Publications, 2019. Chapter 9: "Handling output safely", pp. 247-249.






  1. Ball, Corey. Hacking APIs. No Starch Press, 2022.









🚀 What's Next? Continue Your Security Training



This XSS challenge is just one exercise from a complete Security Engineering curriculum. The SecEng-Exercises repository includes:






Current Exercises (Updated Weekly)




  • ✅ Week 1-5: TCP/IP fundamentals, SQL injection, Python security patterns

  • Week 6: XSS vulnerabilities (you just completed this!)

  • 🔄 Week 7-10: SAST/DAST tools, authentication bypasses, API security

  • 📅 Coming soon: Cryptographic attacks, race conditions, SSRF, and more






What Makes These Exercises Different?





  1. Battle-tested patterns - Every vulnerability is based on real CVEs and production incidents


  2. Comprehensive testing - 60+ test cases per exercise ensure you truly understand the exploits


  3. Career-focused - Designed to prepare you for Security Engineer interviews at top companies


  4. Open source - Free forever, community-driven, continuously improving






📊 Exercise Difficulty Progression




  • Weeks 1-8: Foundation (beginner-friendly)

  • Weeks 9-16: Intermediate (interview-ready)

  • Weeks 17-24: Advanced (senior-level concepts)






Practice Challenge



Can you identify which vulnerability would cause the most damage in each scenario?





  1. Exercise 1: Which attack vector is most dangerous—the search query or the "no results" message?


  2. Exercise 2: Why doesn't HTML escaping on the server prevent the XSS?


  3. Exercise 3: If you could only fix ONE vulnerability, which would have the biggest security impact?



Star the GitHub repo and share your answers in the Issues tab—I respond to every submission!









🎯 Ready to Level Up Your Security Skills?



If this exercise helped you understand XSS better, imagine mastering:




  • SQL injection with 15 different attack vectors

  • JWT authentication bypasses

  • Race condition exploits

  • Cryptographic timing attacks

  • API rate limit bypasses

  • Server-Side Request Forgery (SSRF)

  • XML External Entity (XXE) attacks



All available for free in the repository.






Take Action Now:





  1. Star the SecEng-Exercises repo - Get notified of new challenges


  2. 🔀 Fork it - Customize exercises for your learning style


  3. 💬 Join discussions - Ask questions, share solutions, help others


  4. 📢 Share - Help other aspiring Security Engineers discover these resources






My Goal



I'm creating the most comprehensive, free, open-source Security Engineering curriculum available. Every week I add new exercises based on real vulnerabilities I've encountered in my career at Intel and from analyzing thousands of CVEs.



Your ⭐ star helps more developers discover these resources and motivates me to create even better content.






Remember: The TechFinance disaster started with a single XSS vulnerability. Don't let it happen to your application.



Master these patterns. Review code carefully. Always assume user input is malicious.






🎓 Continue Your Journey



This is just Week 6 of a 48-week curriculum. Star the SecEng-Exercises repository to follow the complete path from beginner to senior Security Engineer.



Next up: Week 7 covers SAST/DAST tool implementation and code review automation—exercises drop this Friday!






Built by a Security Engineer, for Security Engineers. All exercises are free and open source forever. Star the repo to support the project! ⭐



Repository: https://github.com/fosres/SecEng-Exercises



Stay secure! 🔒

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Week 6 Quiz Audit XSS Vulnerabilities

Thematisch verwandte Begriffe: Week, Quiz, Audit, Vulnerabilities · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-19438 | Improper Limitation of a Pathname to a Restricted Directory ('Path Trave…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick