name parameter being echoed back into the response without any filtering or encoding.July 28, 2026
Cross-Site Scripting (XSS) Exploitation Walkthrough: Reflected and Stored, Across Security Levels
Introduction

By Karim roshdy
4 min read
Introduction
Cross-Site Scripting (XSS) remains one of the most common web application vulnerabilities, allowing an attacker to inject and execute arbitrary JavaScript in the context of a victim's browser. This write-up documents a hands-on exploitation exercise against DVWA (Damn Vulnerable Web Application), covering two major XSS variants — Reflected XSS and Stored XSS — each tested across DVWA's three increasing security/filtering levels: Low, Medium, and High.
The goal of this walkthrough is not just to trigger a proof-of-concept alert() popup, but to document the actual filter-bypass reasoning used at each level: identifying what protection was added, understanding why the initial payload failed, and adapting the payload accordingly.
Part 1: Reflected XSS
Reflected XSS occurs when user-supplied input is immediately echoed back in the server's response without proper sanitization, causing injected script to execute as soon as the page loads.
Low Security Level
At the Low level, the application takes a name input parameter and reflects it directly back into the page output as a greeting (i.e., submitting a name returns "Hello, <name>"), with no input sanitization applied.
Payload used:
<script>alert("XSS")</script><script>alert("XSS")</script>
Medium Security Level
At the Medium level, a filtering rule was added: the application performs a string replacement that strips or neutralizes the word "script" from user input, targeting the literal <script> tag used in the Low-level payload.
Two bypass approaches were identified:
- Case manipulation — since the filter's match on the word "script" is case-sensitive, altering the casing (e.g.,
<scripT>) causes the input to pass through the filter untouched, while still being interpreted correctly by the browser as a valid script tag. - Avoiding the word "script" entirely — switching to a different HTML element altogether (such as an
<img>tag with an event handler) removes any dependency on the filtered keyword.
Payload used:
<scripT>alert("XSS")</script><scripT>alert("XSS")</script>High Security Level
At the High level, the tag-based bypass used at Medium was no longer viable, indicating stronger/more thorough filtering of the word "script" (or the <script> tag structure itself) regardless of casing. The solution was to pivot to a payload that avoids the <script> tag entirely, using an <img> tag with a deliberately broken src attribute and an onerror event handler to execute JavaScript when the image fails to load.
Payload used:
<img src=x onerror=alert("XSS")><img src=x onerror=alert("XSS")>
Part 2: Stored XSS
Stored XSS occurs when injected input is saved server-side (e.g., in a database) and later rendered to other users who view the affected page — meaning the malicious script persists and executes for every visitor, not just the original submitter, until it is removed.
Low Security Level
At the Low level, the input field imposed a character limit (observed as a maximum of roughly 10 characters), which initially prevented entering a full script payload directly.
Bypass approach: the character-limit restriction was a client-side HTML attribute, so it was edited directly in the browser (via the page's HTML/DOM) to remove or extend the limit, after which the full payload could be entered and submitted normally.
Payload used:
<script>alert("XSS")</script><script>alert("XSS")</script>
Medium Security Level
At the Medium level, the same type of character limit was present and was bypassed the same way as at the Low level. Reviewing the page's source code further revealed that input filtering was applied to the message field, but not to the name field — meaning the name field was left as an unfiltered injection point. Additionally, the filter still replaced/broke the literal word "script" when it was detected, so an alternate payload avoiding that keyword was required.
High Security Level
Per the analysis notes, the same bypass approach that succeeded at the Medium level (injecting through the unfiltered field with an adjusted, non-"script"-keyword payload) was found to remain effective at the High security level as well.
Conclusion
This exercise reinforced a core lesson in web application security testing: XSS filters that rely on blacklisting specific keywords or tags (such as stripping the literal word "script") are inherently fragile. Simple techniques — altering tag casing, switching to alternate HTML elements with event handlers (<img onerror>), or targeting an unfiltered input field alongside a filtered one — were consistently enough to bypass each level of protection tested, in both the Reflected and Stored XSS scenarios.
The progression across Low → Medium → High levels also illustrates how real-world filter bypass work operates: each added restriction (keyword stripping, character limits, field-specific filtering) required re-analyzing the application's actual filtering logic rather than reusing the previous payload unmodified. This kind of iterative, source-code-informed testing is a core skill for identifying genuine input validation gaps rather than relying on a single canned payload.
References & Tools
- DVWA (Damn Vulnerable Web Application) — the intentionally vulnerable web application used as the target for both the Reflected and Stored XSS modules, across its Low, Medium, and High security levels.
- Browser Developer Tools — used to inspect and directly edit client-side HTML attributes (e.g., removing the input character-limit restriction) and to review page/application source code for filter logic.
- Manual payload crafting —
<script>alert("XSS")</script>,<scripT>alert("XSS")</script>, and<img src=x onerror=alert("XSS")>, each adapted based on the specific filtering behavior observed at each security level.
This write-up documents a hands-on Reflected and Stored XSS exploitation exercise performed as practical web application security testing, walking through progressively stricter filter-bypass techniques.