Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Protecting a Java application from cross-site scripting (XSS) means keeping untrusted data out of executable browser contexts. Validate fields with known formats, then encode each value for the exact place it is rendered; sanitize only when users are intentionally allowed to submit a limited subset of HTML. Framework auto-escaping and a carefully configured Content Security Policy (CSP) add protection, but neither replaces safe output handling.

How XSS happens in a Java application

XSS occurs when a browser interprets attacker-controlled content as code rather than as data. A value can arrive in a request parameter, form field, header, cookie, imported file, third-party API response, or a database record that originally came from a user. Storing a value in a database does not make it trustworthy.

There are three common paths to review:

  • Reflected XSS: a request value is included in a response, such as a search page that echoes a query.
  • Stored XSS: a submitted value is saved and later rendered to one or more users, such as a comment or profile field.
  • DOM-based XSS: client-side JavaScript moves an untrusted value into a browser sink that parses it as HTML or code.

OWASP’s guidance is to combine defenses: no single technique prevents every XSS path. Keep values as data through application and persistence layers, and apply the right protection where each value reaches an output context.

Use validation, encoding, and sanitization for different jobs

Validate constrained fields

When a field has a defined grammar, accept only values that fit it. For example, validate an identifier against its permitted characters and length, or accept an enumeration only from the known set of values. This prevents unexpected input from entering workflows and storage.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Validation does not replace output encoding. A value valid as a name, label, or search term can still be dangerous if inserted into the wrong browser context. Treat validation as an additional control, not as proof that a value is safe to render everywhere.

Encode ordinary text at the output sink

For plain text, encode when rendering, using an encoder designed for the destination context. HTML body text needs characters such as &, <, >, quotation marks, and apostrophes represented safely so the browser displays them rather than interpreting markup. Attribute, URL, JavaScript, and CSS contexts have different parsing rules and require different handling.

In Java, prefer the OWASP Java Encoder’s context-specific APIs over a hand-built chain of replace() calls. Choose the method for the sink you are writing to; HTML encoding is not a universal escape operation.

Sanitize only when a limited amount of HTML is a product feature

If a feature deliberately accepts formatted comments or similar rich text, encoding the entire value would display the markup literally. Instead, pass it through a maintained HTML sanitizer configured with a narrow policy describing the elements and attributes the feature needs. OWASP recommends using Java Encoder and Java HTML Sanitizer together as defense in depth.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For ordinary names, messages, or descriptions that do not need formatting, render text with output encoding rather than accepting HTML. Do not allow arbitrary rich HTML or trust a value merely because it was sanitized at an earlier point: render it only in the intended context and preserve the sanitizer’s policy boundary.

Match protection to the browser context

HTML is parsed in multiple contexts. A value safe as visible text may not be safe inside an attribute, a URL, a script, or a style block. The safest design is to avoid placing untrusted values in executable contexts altogether.

Destination Safer handling Important boundary
HTML body text Use HTML text encoding. Do not treat encoded text as sanitized rich HTML.
HTML attribute Quote the complete attribute value, use attribute-context encoding, and allow only attributes the feature needs. Encoding does not make an event-handler attribute or other executable attribute safe.
URL parameter in a link or resource URL Percent-encode the parameter value, then HTML-attribute-encode the complete URL when placing it in href or src. For user-controlled links, validate allowed schemes and hosts; encoding alone does not make a dangerous scheme safe.
JavaScript data Prefer not to interpolate server values into scripts. If required, keep values in quoted data strings and use JavaScript-context encoding. Never concatenate input into executable code, function names, or event handlers.
CSS Avoid inserting user data into CSS. If unavoidable, validate narrowly and use CSS-specific encoding. HTML or JavaScript encoding does not protect a CSS value.

Do not place untrusted values directly in script blocks, inline event handlers, CSS, HTML comments, script URLs, or other locations where the browser can interpret them as code. A value crossing more than one context needs protection appropriate to each boundary; the better fix is usually to restructure the output so it crosses fewer contexts.

Use Java libraries and template protections safely

Prefer established encoders over custom escaping

Use the OWASP Java Encoder API that corresponds to the output sink. A single generic “escape” helper is a warning sign if it is used for HTML, attributes, JavaScript, and URLs alike. Keep encoding close to the rendering operation so developers can see which context is being protected.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep template auto-escaping enabled

Template engines and modern frameworks can reduce XSS risk by escaping ordinary text automatically. In Thymeleaf, use escaped text expressions for untrusted content; do not use unescaped HTML expressions unless that value has passed through the intended sanitizer. Audit JSP expression output and helper methods that write raw HTML. An auto-escaping default cannot protect code paths that deliberately bypass it.

Audit every route around the framework

Review raw HTML helpers, unsafe template features, outdated components or plugins, and client-side code that handles server-provided values. The same stored value may be rendered in several views, each with a different context; protect each sink rather than assuming that an earlier template or input check covers all uses.

Prevent DOM-based XSS in client-side code

Server-side encoding does not automatically make later JavaScript safe. Avoid assigning untrusted strings to innerHTML, outerHTML, or document.write, and do not pass them to eval-like APIs, script URLs, or inline event handlers. For content intended to be text, use text-only sinks such as textContent. Construct URLs safely and validate their schemes and, where relevant, hosts.

When a value must cross server-rendered and JavaScript contexts, use the correct encoding at each boundary rather than relying on one layer’s escaping. Trace the value from its source through any template or client-side transformation to the final DOM sink.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Add CSP as a second layer in Spring Security

A Content Security Policy can limit which scripts a browser is allowed to run, reducing the impact of an injection that escaped other defenses. Configure a policy through Spring Security’s response-header support and tailor it to the application’s actual resources. Spring Security’s documentation cautions that CSP is not intended to solve all content-injection vulnerabilities.

As a starting design, restrict script sources to the application’s trusted sources, avoid 'unsafe-inline' and 'unsafe-eval' where practical, and use per-response nonces or hashes for intentional inline scripts. A nonce must be unpredictable and consistently associated with the permitted script and that response’s policy; a fixed example value is not a safe production nonce. Test the policy against required scripts and integrations before enforcing it, and use CSP violation reporting to identify unexpected loads or blocked behavior.

Do not rely on the X-XSS-Protection response header as a modern XSS defense. Spring Security documents its browser filter as deprecated and the header as disabled by default with value 0. CSP, cookies, CSRF tokens, and a web application firewall can be useful supporting controls, but none substitutes for context-appropriate output encoding or sanitization.

Why request-wide sanitizing filters are not enough

A servlet filter or Spring interceptor that attempts to sanitize every incoming request cannot know how each value will later be used. It can miss data from cookies or other sources, alter legitimate input, and apply HTML handling to values that may eventually be rendered in a different context. It also separates the security decision from the output sink where the browser’s parsing rules matter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep the original data available to application logic, validate fields according to their business rules, and encode or sanitize at the point of rendering. A shared output helper is useful when it makes the context explicit; a global input-rewriting layer is not a replacement for that decision.

Review and test the complete rendering path

  1. Map sources and sinks. Identify request values, headers, cookies, user-originated database fields, imports, and third-party data. Find every template, response builder, and client-side DOM operation that renders them.
  2. Classify each sink. Record whether a value becomes HTML text, an attribute, a URL, JavaScript data, CSS, or deliberately allowed rich HTML.
  3. Check the control at that sink. Confirm the matching encoder is used, a rich-text policy is narrow and maintained, and framework escape hatches are justified and protected.
  4. Exercise representative hostile-looking values in a controlled test environment. Include quotes, angle brackets, entity-looking strings, URL schemes, and context-breaking sequences. Verify in the rendered browser output that ordinary text remains text and rich text is restricted to the allowed subset.
  5. Review browser-side code and headers. Trace values to DOM sinks and check that the CSP permits required resources without opening avoidable script execution paths. Investigate unexpected CSP violation reports.

Testing should cover reflected, stored, and DOM-based paths, including all views that render the same stored value. A passing test for one template does not establish that another output context is safe.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.