java.lang.security.audit.permissive-cors.permissive-cors

Verifed by r2c
Community Favorite
profile photo of semgrepsemgrep
Author
98,391
Download Count*

https://find-sec-bugs.github.io/bugs.htm#PERMISSIVE_CORS Permissive CORS policy will allow a malicious application to communicate with the victim application in an inappropriate way, leading to spoofing, data theft, relay and other attacks.

Run Locally

Run in CI

Defintion

rules:
  - id: permissive-cors
    message: https://find-sec-bugs.github.io/bugs.htm#PERMISSIVE_CORS Permissive
      CORS policy will allow a malicious application to communicate with the
      victim application in an inappropriate way, leading to spoofing, data
      theft, relay and other attacks.
    metadata:
      cwe:
        - "CWE-183: Permissive List of Allowed Inputs"
      asvs:
        section: "V14: Configuration Verification Requirements"
        control_id: 14.4.8 Permissive CORS
        control_url: https://github.com/OWASP/ASVS/blob/master/4.0/en/0x22-V14-Config.md#v144-http-security-headers-requirements
        version: "4"
      category: security
      technology:
        - java
      owasp:
        - A04:2021 - Insecure Design
      references:
        - https://owasp.org/Top10/A04_2021-Insecure_Design
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Improper Validation
    severity: WARNING
    languages:
      - java
    pattern-either:
      - pattern: |
          HttpServletResponse $RES = ...;
          ...
          $RES.addHeader("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
      - pattern: |
          HttpServletResponse $RES = ...;
          ...
          $RES.setHeader("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
      - pattern: >
          ServerHttpResponse $RES = ...;

          ...

          $RES.getHeaders().add("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
      - pattern: |
          HttpHeaders $HEADERS = ...;
          ...
          $HEADERS.set("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
      - pattern: >
          ServerWebExchange $SWE = ...;

          ...

          $SWE.getResponse().getHeaders().add("Access-Control-Allow-Origin", "*");
      - pattern: >
          $X $METHOD(...,HttpServletResponse $RES,...) {
            ...
            $RES.addHeader("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
            ...
          }
      - pattern: >
          $X $METHOD(...,HttpServletResponse $RES,...) {
            ...
            $RES.setHeader("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
            ...
          }
      - pattern: >
          $X $METHOD(...,ServerHttpResponse $RES,...) {
            ...
            $RES.getHeaders().add("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
            ...
          }
      - pattern: >
          $X $METHOD(...,ServerWebExchange $SWE,...) {
            ...
            $SWE.getResponse().getHeaders().add("=~/access-control-allow-origin/i", "=~/^\*|null$/i");
            ...
          }
      - pattern: ResponseEntity.$RES().header("=~/access-control-allow-origin/i",
          "=~/^\*|null$/i")
      - pattern: ServerResponse.$RES().header("=~/access-control-allow-origin/i",
          "=~/^\*|null$/i")

Examples

permissive-cors.java

package foolet;

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;

/**
 * Servlet implementation class SuperWebFlet
 */
@WebServlet("/SuperWebFlet")
public class SuperWebFlet extends HttpServlet {

    public SuperWebFlet() {
        // Auto-generated constructor stub
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        // ruleid: permissive-cors
        HttpServletResponse res = (HttpServletResponse) response;
        res.addHeader("Access-Control-Allow-Origin", "*");
        chain.doFilter(request, response);
    }

    // ruleid: permissive-cors
    @GetMapping({"", "/"})
    @PreAuthorize("hasPermission('User', 'read')")
    public List index(HttpServletRequest request, HttpServletResponse response) {
        response.addHeader("access-control-allow-origin", "*");
        return page.getContent().stream().map((item) -> {
            Map<String, Object> ret = new HashMap();
            ret.put("createdAt", item.getCreatedAt());
            return ret;
        }).collect(Collectors.toList());
    }

    // ruleid: permissive-cors
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html; charset=UTF-8");
            response.setHeader("Access-Control-Allow-Origin", "Null");
            boolean ok = "OK".equals(ibookDbStatus);
            if (!ok) {
                response.setStatus(500);
            }
        }
        catch (RuntimeException | IOException e) {
            logger.log(Level.SEVERE, "RQ[HEALT] -> "+e.toString(), e);
            throw e;
        }
    }

    // ruleid: permissive-cors
    public void setErrorsResponse(Errors errors, HttpStatus responseHttpStatus, HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setStatus(responseHttpStatus.value());
        HttpResponseData responseData = getResponseData(errors, request);
        if (responseData != null) {
            response.addHeader("access-control-allow-origin", "*");
            response.getWriter().write(responseData.getBody());
        }
    }

    // ruleid: permissive-cors
    public static void write(HttpServletResponse response, Object o) throws Exception {
        response.setContentType("text/html;charset=utf-8");
        response.addHeader("Access-Control-Allow-Origin", "*.test.com");
        PrintWriter out = response.getWriter();
        out.println(o.toString());
        out.flush();
        out.close();
    }

    @GetMapping("/response-entity-builder-with-http-headers")
    public ResponseEntity<String> usingResponseEntityBuilderAndHttpHeaders() {
        // ruleid: permissive-cors
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set("Access-Control-Allow-Origin", "*");

        return ResponseEntity.ok()
        .headers(responseHeaders)
        .body("Response with header using ResponseEntity");
    }

    // ruleid: permissive-cors
    @GetMapping("/server-http-response")
    public Mono<String> usingServerHttpResponse(ServerHttpResponse response) {
        response.getHeaders().add("Access-Control-Allow-Origin", "*");
        return Mono.just("Response with header using ServerHttpResponse");
    }

    @GetMapping("/response-entity")
    public Mono<ResponseEntity<String>> usingResponseEntityBuilder() {
        String responseBody = "Response with header using ResponseEntity (builder)";
        // ruleid: permissive-cors
        return Mono.just(ResponseEntity.ok()
        .header("Access-Control-Allow-Origin", "*")
        .body(responseBody));
    }

    public Mono<ServerResponse> useHandler(final ServerRequest request) {
     // ruleid: permissive-cors
     return ServerResponse.ok()
        .header("Access-Control-Allow-Origin", "null")
        .body(Mono.just("Response with header using Handler"),String.class);
    }

    // ruleid: permissive-cors
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        exchange.getResponse()
            .getHeaders()
            .add("Access-Control-Allow-Origin", "*.some.domain");
        return chain.filter(exchange);
    }

    // ok: permissive-cors
    public void setErrorsResponse1(Errors errors, HttpStatus responseHttpStatus, HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.addHeader("Foo", "Bar");
        response.getWriter().write(responseData.getBody());
    }

    // ok: permissive-cors
    @GetMapping("/ok-ok")
    public Mono<String> usingServerHttpResponse1(ServerHttpResponse response) {
        response.getHeaders().add("Foo", "Bar");
        return Mono.just("Response with header using ServerHttpResponse");
    }

    @GetMapping("/ok-ok-ok")
    public ResponseEntity<String> usingResponseEntityBuilderAndHttpHeaders1() {
        // ok: permissive-cors
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set("Foo", "Bar");

        return ResponseEntity.ok()
        .headers(responseHeaders)
        .body("Response with header using ResponseEntity");
    }

}