Java Servlet Response Writer XSS

High Risk Cross-site Scripting
xssjavaservletresponse-writerhtml-encoding

What it is

Cross-site scripting (XSS) vulnerability in Java Servlet applications where user input is written directly to HTTP response using PrintWriter without proper HTML encoding.

@WebServlet("/user-profile")
public class UserProfileServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request,
                        HttpServletResponse response) throws IOException {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        // Vulnerable: No encoding of user input
        String name = request.getParameter("name");
        String message = request.getParameter("message");
        String theme = request.getParameter("theme");

        // XSS vulnerability - direct output
        out.println("<html><head><title>Profile</title></head><body>");
        out.println("<h1>Welcome " + name + "!</h1>");
        out.println("<p>Message: " + message + "</p>");
        out.println("<div class='" + theme + "'>Content</div>");
        out.println("</body></html>");

        out.close();
    }

    protected void doPost(HttpServletRequest request,
                         HttpServletResponse response) throws IOException {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        // Vulnerable form processing
        String comment = request.getParameter("comment");
        String author = request.getParameter("author");

        // Direct string concatenation - XSS risk
        out.println("<div class='comment-section'>");
        out.println("<h3>Comment by: " + author + "</h3>");
        out.println("<p>" + comment + "</p>");
        out.println("</div>");

        out.close();
    }
}

/* Attack vectors:
?name=<script>alert('XSS')</script>
?message=<img src=x onerror="fetch('/admin/delete-user')">
?theme=" onload="document.location='//evil.com'
comment=<script>document.cookie='stolen'</script>
*/
import org.owasp.encoder.Encode;
import com.fasterxml.jackson.databind.ObjectMapper;

@WebServlet("/user-profile")
public class UserProfileServlet extends HttpServlet {

    private static final ObjectMapper mapper = new ObjectMapper();

    protected void doGet(HttpServletRequest request,
                        HttpServletResponse response) throws IOException {

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        // Safe: HTML encoding all user input
        String name = request.getParameter("name");
        String message = request.getParameter("message");
        String theme = request.getParameter("theme");

        // Validate theme against whitelist
        String[] allowedThemes = {"light", "dark", "blue"};
        String safeTheme = Arrays.asList(allowedThemes).contains(theme) ? theme : "light";

        out.println("<html><head><title>Profile</title></head><body>");
        out.println("<h1>Welcome " + Encode.forHtml(name) + "!</h1>");
        out.println("<p>Message: " + Encode.forHtml(message) + "</p>");
        out.println("<div class='" + safeTheme + "'>Content</div>");
        out.println("</body></html>");

        out.close();
    }

    protected void doPost(HttpServletRequest request,
                         HttpServletResponse response) throws IOException {

        String comment = request.getParameter("comment");
        String author = request.getParameter("author");

        // Option 1: HTML Response with encoding
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        out.println("<div class='comment-section'>");
        out.println("<h3>Comment by: " + Encode.forHtml(author) + "</h3>");
        out.println("<p>" + Encode.forHtml(comment) + "</p>");
        out.println("</div>");
        out.close();

        // Option 2: JSON API response (recommended)
        /*
        response.setContentType("application/json;charset=UTF-8");

        Map<String, Object> result = new HashMap<>();
        result.put("author", author);
        result.put("comment", comment);
        result.put("timestamp", new Date());

        String json = mapper.writeValueAsString(result);
        response.getWriter().write(json);
        */
    }
}

// Alternative: Using JSP with JSTL (views/profile.jsp)
/*
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>Profile</title></head>
<body>
    <h1>Welcome <c:out value="${param.name}" />!</h1>
    <p>Message: <c:out value="${param.message}" /></p>
    <div class="<c:out value='${safeTheme}' />">Content</div>
</body>
</html>
*/

💡 Why This Fix Works

The vulnerable code writes user input directly to HTTP response without encoding. The fixed version uses OWASP Encoder for HTML encoding and input validation.

Why it happens

Writing user input directly to HttpServletResponse PrintWriter without HTML encoding allows script injection.

Root causes

Direct PrintWriter Output Without Encoding

Writing user input directly to HttpServletResponse PrintWriter without HTML encoding allows script injection.

Preview example – JAVA
// Vulnerable
String name = request.getParameter("name");
out.println("<h1>Welcome " + name + "!</h1>");

Unvalidated Parameter Output

Using request parameters directly in HTML output without validation or encoding creates XSS vulnerabilities.

Preview example – JAVA
// Vulnerable
String theme = request.getParameter("theme");
out.println("<div class='" + theme + "'>Content</div>");

Fixes

1

Use OWASP Java Encoder for HTML Encoding

Use the OWASP Java Encoder library to properly encode user input before writing to HTTP response.

View implementation – JAVA
import org.owasp.encoder.Encode;

// Safe: HTML encoding
String name = request.getParameter("name");
out.println("<h1>Welcome " + Encode.forHtml(name) + "!</h1>");
2

Use JSP with JSTL for Auto-Escaping

Use JSP with JSTL tags that provide automatic HTML escaping for user input.

View implementation – JSP
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h1>Welcome <c:out value="${param.name}" />!</h1>

Detect This Vulnerability in Your Code

Sourcery automatically identifies java servlet response writer xss and many other security issues in your codebase.