A cross-site scripting vulnerability, or XSS, is a flaw that lets an attacker inject JavaScript that runs in another user's browser in the context of your site, and you fix it primarily by encoding untrusted data on output rather than trusting it as safe. XSS remains one of the most common web weaknesses because any place your application reflects user-controlled data into a page is a candidate. This guide explains the vulnerability conceptually, shows a cross site scripting example in JavaScript for illustration, and gives concrete cross site scripting prevention in Java — all framed defensively, for detection and remediation.
What actually happens in an XSS attack
When a page includes data that came from a user and treats it as markup instead of text, the browser will execute any script in that data. The attacker's goal is usually to steal session cookies or tokens, perform actions as the victim, or rewrite the page to phish credentials. Because the script runs with your site's origin, it inherits your users' trust.
Here is an illustrative cross site scripting example javascript developers recognize — a reflected sink that never encodes its input:
// Vulnerable: writes untrusted input straight into the DOM as HTML
const q = new URLSearchParams(location.search).get('q')
document.getElementById('results').innerHTML = 'You searched for: ' + q
If q contains an img tag with an onerror handler, the browser runs it. The fix is not to filter cleverer strings; it is to stop treating input as HTML. This is a conceptual demonstration of the sink, not an exploit payload against any real target.
The three types you need to recognize
Reflected XSS bounces untrusted input straight back in the response — search results, error messages echoing a parameter. It requires tricking a victim into a crafted request.
Stored XSS is worse: the malicious input is saved (a comment, a profile field, a support ticket) and served to everyone who views it later. One injection hits many victims.
DOM-based XSS never involves the server rendering the payload. Client-side JavaScript reads from a source like location.hash and writes to a dangerous sink like innerHTML entirely in the browser. It is easy to miss because server-side scanning cannot see it.
Recognizing which type you have tells you where to fix it — server templates, storage-and-render paths, or client-side code.
The core fix: context-aware output encoding
The durable fix for a cross site scripting vulnerability is encoding data for the context where it lands. The same string is safe in one place and dangerous in another. HTML body context needs HTML entity encoding; an HTML attribute needs attribute encoding; inside a <script> block or a URL, different rules apply again. Do not write your own encoder — use a vetted library and let it choose the encoding for the context.
In the DOM, the simplest safe pattern is to avoid innerHTML for untrusted data entirely:
// Safe: textContent never interprets input as markup
document.getElementById('results').textContent = 'You searched for: ' + q
When you genuinely must render user-supplied HTML (a rich-text field), sanitize it with a maintained library such as DOMPurify rather than a regex. Our DOMPurify npm guide covers that path in detail.
How to fix cross site scripting vulnerability in Java
For server-rendered Java applications, the how to fix cross site scripting vulnerability in java example most teams need is contextual output encoding with the OWASP Java Encoder. Encode at the point of output, choosing the method that matches the context:
import org.owasp.encoder.Encode;
// HTML body context
out.write(Encode.forHtml(userInput));
// HTML attribute context
String attr = Encode.forHtmlAttribute(userInput);
// Inside a URL
String url = "/profile?name=" + Encode.forUriComponent(userInput);
Modern templating helps. JSP with JSTL <c:out> escapes by default; Thymeleaf's th:text escapes while th:utext does not, so treat th:utext as a red flag in review. Combine encoding with input validation: reject or constrain input that should never contain markup (an email field, a numeric ID) as defense in depth. Cross site scripting prevention java programs get right is layered — encode on output, validate on input, and set the response headers below.
Content Security Policy and other layers
Encoding is your primary control; a Content Security Policy is the safety net that limits damage if an encoding gap slips through. A strict CSP that disallows inline script and restricts script sources means an injected <script> often will not execute even if it reaches the page:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'
Set cookies HttpOnly so injected script cannot read session tokens, and Secure so they only travel over TLS. Use framework auto-escaping (React escapes by default; avoid dangerouslySetInnerHTML). None of these replace encoding, but together they turn a single missed sink from a full compromise into a contained one.
Finding XSS before attackers do
You cannot encode a sink you do not know exists. Static analysis (SAST) traces untrusted input from source to sink in your own code, and dynamic testing probes the running application to confirm exploitability — especially valuable for DOM-based XSS that static tools miss. Run both in CI so a newly introduced innerHTML on user data fails the pipeline rather than shipping. The combination of layered code fixes and automated detection is what keeps XSS from recurring.
FAQ
What is a cross-site scripting vulnerability?
It is a flaw that lets an attacker inject JavaScript that runs in another user's browser under your site's origin. Because the script runs with your users' trust, attackers use it to steal session tokens, act as the victim, or phish. It occurs wherever untrusted data is treated as markup.
How do I fix a cross-site scripting vulnerability in Java?
Encode output for its context using a vetted library like the OWASP Java Encoder — Encode.forHtml, Encode.forHtmlAttribute, and so on — at the point of output. Rely on auto-escaping templating (JSTL <c:out>, Thymeleaf th:text), validate input as defense in depth, and add a Content Security Policy.
What are the three types of XSS?
Reflected XSS echoes input back in the immediate response, stored XSS saves the payload and serves it to many later viewers, and DOM-based XSS occurs entirely in client-side JavaScript reading a source and writing a dangerous sink. Each needs fixing at a different point in the request flow.
Does a Content Security Policy fix XSS on its own?
No. Output encoding is the primary fix; CSP is a safety net that limits damage when an encoding gap slips through by blocking inline and untrusted scripts. Combine CSP with encoding, HttpOnly cookies, and framework auto-escaping for layered protection.