java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer

profile photo of semgrepsemgrep
Author
6,309
Download Count*

Detected a request with potential user-input going into a OutputStream or Writer object. This bypasses any view or template environments, including HTML escaping, which may expose this application to cross-site scripting (XSS) vulnerabilities. Consider using a view technology such as JavaServer Faces (JSFs) which automatically escapes HTML views.

Run Locally

Run in CI

Defintion

rules:
  - id: no-direct-response-writer
    message: Detected a request with potential user-input going into a OutputStream
      or Writer object. This bypasses any view or template environments,
      including HTML escaping, which may expose this application to cross-site
      scripting (XSS) vulnerabilities. Consider using a view technology such as
      JavaServer Faces (JSFs) which automatically escapes HTML views.
    severity: WARNING
    options:
      interfile: true
    metadata:
      likelihood: HIGH
      impact: MEDIUM
      confidence: MEDIUM
      category: security
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation
          ('Cross-site Scripting')"
      cwe2021-top25: true
      cwe2022-top25: true
      owasp:
        - A07:2017 - Cross-Site Scripting (XSS)
        - A03:2021 - Injection
      references:
        - https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaServerFaces.html
      subcategory:
        - vuln
      technology:
        - java
        - servlets
      interfile: true
      license: proprietary license - copyright © Semgrep, Inc.
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    languages:
      - java
    mode: taint
    pattern-sources:
      - patterns:
          - pattern-either:
              - pattern: |
                  (HttpServletRequest $REQ).$REQFUNC(...)
              - pattern: |
                  (ServletRequest $REQ).$REQFUNC(...) 
          - metavariable-regex:
              metavariable: $REQFUNC
              regex: (getInputStream|getParameter|getParameterMap|getParameterValues|getReader|getCookies|getHeader|getHeaderNames|getHeaders|getPart|getParts|getQueryString)
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern: |
                  (HttpServletResponse $RESPONSE).getWriter(...).$WRITE(...)
              - pattern: >
                  (HttpServletResponse
                  $RESPONSE).getOutputStream(...).$WRITE(...)
              - pattern: |
                  (java.io.PrintWriter $WRITER).$WRITE(...)
              - pattern: |
                  (PrintWriter $WRITER).$WRITE(...)
              - pattern: |
                  (javax.servlet.ServletOutputStream $WRITER).$WRITE(...)
              - pattern: |
                  (ServletOutputStream $WRITER).$WRITE(...)
              - pattern: |
                  (java.io.OutputStream $WRITER).$WRITE(...)
              - pattern: |
                  (OutputStream $WRITER).$WRITE(...)
    pattern-sanitizers:
      - pattern-either:
          - pattern: Encode.forHtml(...)
          - pattern: (PolicyFactory $POLICY).sanitize(...)
          - pattern: (AntiSamy $AS).scan(...)
          - pattern: JSoup.clean(...)
          - pattern: org.apache.commons.lang.StringEscapeUtils.escapeHtml(...)
          - pattern: org.springframework.web.util.HtmlUtils.htmlEscape(...)
          - pattern: org.owasp.esapi.ESAPI.encoder().encodeForHTML(...)

Examples

no-direct-response-writer.java

/**
* OWASP Benchmark Project v1.2
*
* This file is part of the Open Web Application Security Project (OWASP)
* Benchmark Project. For details, please see
* <a href="https://www.owasp.org/index.php/Benchmark">https://www.owasp.org/index.php/Benchmark</a>.
*
* The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation, version 2.
*
* The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* @author Nick Sanidas <a href="https://www.aspectsecurity.com">Aspect Security</a>
* @created 2015
*/

package org.owasp.benchmark.testcode;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(value="/xss-04/BenchmarkTest02229")
public class BenchmarkTest02229 extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        java.util.Map<String,String[]> map = request.getParameterMap();
        String param = "";
        if (!map.isEmpty()) {
            String[] values = map.get("BenchmarkTest02229");
            if (values != null) param = values[0];
        }


        String bar = doSomething(request, param);

response.setHeader("X-XSS-Protection", "0");
        Object[] obj = { "a", bar};
        // ruleid: no-direct-response-writer
        response.getWriter().printf(java.util.Locale.US,"Formatted like: %1$s and %2$s.",obj);
    }  // end doPost


    private static String doSomething(HttpServletRequest request, String param) throws ServletException, IOException {

        String bar = "safe!";
        java.util.HashMap<String,Object> map26903 = new java.util.HashMap<String,Object>();
        map26903.put("keyA-26903", "a_Value"); // put some stuff in the collection
        map26903.put("keyB-26903", param); // put it in a collection
        map26903.put("keyC", "another_Value"); // put some stuff in the collection
        bar = (String)map26903.get("keyB-26903"); // get it back out
        bar = (String)map26903.get("keyA-26903"); // get safe value back out

        return bar;
    }
}

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(value="/hash-02/BenchmarkTest02388")
public class BenchmarkTest02388 extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        org.owasp.benchmark.helpers.SeparateClassRequest scr = new org.owasp.benchmark.helpers.SeparateClassRequest( request );
        String param = scr.getTheParameter("BenchmarkTest02388");
        if (param == null) param = "";

        String bar = doSomething(request, param);

        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] input = { (byte)'?' };
            Object inputParam = bar;
            if (inputParam instanceof String) input = ((String) inputParam).getBytes();
            if (inputParam instanceof java.io.InputStream) {
                byte[] strInput = new byte[1000];
                int i = ((java.io.InputStream) inputParam).read(strInput);
                if (i == -1) {
                    // ok: no-direct-response-writer
                    response.getWriter().println(
"This input source requires a POST, not a GET. Incompatible UI for the InputStream source."
);
                    return;
                }
                input = java.util.Arrays.copyOf(strInput, i);
            }
            md.update(input);

            byte[] result = md.digest();
            java.io.File fileTarget = new java.io.File(
                    new java.io.File(org.owasp.benchmark.helpers.Utils.testfileDir),"passwordFile.txt");
            java.io.FileWriter fw = new java.io.FileWriter(fileTarget,true); //the true will append the new data
                fw.write("hash_value=" + org.owasp.esapi.ESAPI.encoder().encodeForBase64(result, true) + "\n");
            fw.close();
            response.getWriter().println(
            // ok: no-direct-response-writer
            "Sensitive value '" + org.owasp.esapi.ESAPI.encoder().encodeForHTML(new String(input)) + "' hashed and stored<br/>"
);

        } catch (java.security.NoSuchAlgorithmException e) {
            System.out.println("Problem executing hash - TestCase");
            throw new ServletException(e);
        }

        // OK because constant string
        // ok: no-direct-response-writer
        response.getWriter().println(
"Hash Test java.security.MessageDigest.getInstance(java.lang.String) executed"
);
    }  // end doPost


    private static String doSomething(HttpServletRequest request, String param) throws ServletException, IOException {

        String bar = "safe!";
        java.util.HashMap<String,Object> map94322 = new java.util.HashMap<String,Object>();
        map94322.put("keyA-94322", "a_Value"); // put some stuff in the collection
        map94322.put("keyB-94322", param); // put it in a collection
        map94322.put("keyC", "another_Value"); // put some stuff in the collection
        bar = (String)map94322.get("keyB-94322"); // get it back out
        bar = (String)map94322.get("keyA-94322"); // get safe value back out

        return bar;
    }
}


import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(value = "/xss-04/BenchmarkTest02229")
public class BenchmarkTest02229 extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        java.util.Map<String, String[]> map = request.getParameterMap();
        String param = "";
        if (!map.isEmpty()) {
            String[] values = map.get("BenchmarkTest02229");
            if (values != null) param = values[0];
        }

        String bar = doSomething(request, param);

        response.setHeader("X-XSS-Protection", "0");
        Object[] obj = {"a", bar};
        // ruleid: no-direct-response-writer
        response.getWriter().printf(java.util.Locale.US, "Formatted like: %1$s and %2$s.", obj);
    } // end doPost

    private static String doSomething(HttpServletRequest request, String param)
            throws ServletException, IOException {

        String bar = "safe!";
        java.util.HashMap<String, Object> map26903 = new java.util.HashMap<String, Object>();
        map26903.put("keyA-26903", "a_Value"); // put some stuff in the collection
        map26903.put("keyB-26903", param); // put it in a collection
        map26903.put("keyC", "another_Value"); // put some stuff in the collection
        bar = (String) map26903.get("keyB-26903"); // get it back out
        bar = (String) map26903.get("keyA-26903"); // get safe value back out

        return bar;
    }
}

@WebServlet(value = "/xss-00/BenchmarkTest00013")
public class BenchmarkTest00013 extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // some code
        response.setContentType("text/html;charset=UTF-8");

        String param = "";
        java.util.Enumeration<String> headers = request.getHeaders("Referer");

        if (headers != null && headers.hasMoreElements()) {
            param = headers.nextElement(); // just grab first element
        }

        // URL Decode the header value since req.getHeaders() doesn't. Unlike req.getParameters().
        param = java.net.URLDecoder.decode(param, "UTF-8");

        response.setHeader("X-XSS-Protection", "0");
        Object[] obj = {"a", "b"};
        // ruleid: no-direct-response-writer
        response.getWriter().format(java.util.Locale.US, param, obj);
    }
}

/**
 * OWASP Benchmark Project v1.2
 *
 * <p>This file is part of the Open Web Application Security Project (OWASP) Benchmark Project. For
 * details, please see <a
 * href="https://owasp.org/www-project-benchmark/">https://owasp.org/www-project-benchmark/</a>.
 *
 * <p>The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation, version 2.
 *
 * <p>The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU General Public License for more details.
 *
 * @author Nick Sanidas
 * @created 2015
 */
package org.owasp.benchmark.testcode;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(value = "/xss-04/BenchmarkTest02221")
public class BenchmarkTest02221 extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        java.util.Map<String, String[]> map = request.getParameterMap();
        String param = "";
        if (!map.isEmpty()) {
            String[] values = map.get("BenchmarkTest02221");
            if (values != null) param = values[0];
        }

        String bar = doSomething(request, param);

        response.setHeader("X-XSS-Protection", "0");
        Object[] obj = {"a", bar};
        java.io.PrintWriter out = response.getWriter();
        out.write("<!DOCTYPE html>\n<html>\n<body>\n<p>");
        // ruleid: no-direct-response-writer
        out.format(java.util.Locale.US, "Formatted like: %1$s and %2$s.", obj);
        out.write("\n</p>\n</body>\n</html>");
    } // end doPost

    private static String doSomething(HttpServletRequest request, String param)
            throws ServletException, IOException {

        String bar = param;
        if (param != null && param.length() > 1) {
            StringBuilder sbxyz71523 = new StringBuilder(param);
            bar = sbxyz71523.replace(param.length() - "Z".length(), param.length(), "Z").toString();
        }

        return bar;
    }
}