scala.play.security.tainted-html-response.tainted-html-response

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Detected a request with potential user-input going into an Ok() response. 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 Twirl which automatically escapes HTML views.

Run Locally

Run in CI

Defintion

rules:
  - id: tainted-html-response
    mode: taint
    metadata:
      category: security
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation
          ('Cross-site Scripting')"
      owasp:
        - A07:2017 - Cross-Site Scripting (XSS)
        - A03:2021 - Injection
      technology:
        - scala
        - play
      confidence: MEDIUM
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - vuln
      likelihood: HIGH
      impact: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    message: Detected a request with potential user-input going into an `Ok()`
      response. 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 Twirl which
      automatically escapes HTML views.
    pattern-sources:
      - patterns:
          - pattern-either:
              - patterns:
                  - pattern: $REQ
                  - pattern-either:
                      - pattern-inside: |
                          Action {
                            $REQ: Request[$T] => 
                              ...
                          }
                      - pattern-inside: |
                          Action(...) {
                            $REQ: Request[$T] => 
                              ...
                          }
                      - pattern-inside: |
                          Action.async {
                            $REQ: Request[$T] => 
                              ...
                          }
                      - pattern-inside: |
                          Action.async(...) {
                            $REQ: Request[$T] => 
                              ...
                          }
              - patterns:
                  - pattern: $PARAM
                  - pattern-either:
                      - pattern-inside: |
                          def $CTRL(..., $PARAM: $TYPE, ...) = Action {
                            ...
                          }
                      - pattern-inside: |
                          def $CTRL(..., $PARAM: $TYPE, ...) = Action(...) {
                            ...
                          }
                      - pattern-inside: |
                          def $CTRL(..., $PARAM: $TYPE, ...) = Action.async {
                            ...
                          }
                      - pattern-inside: >
                          def $CTRL(..., $PARAM: $TYPE, ...) = Action.async(...)
                          {
                            ...
                          }
    pattern-sanitizers:
      - pattern-either:
          - pattern: org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(...)
          - pattern: org.owasp.encoder.Encode.forHtml(...)
    pattern-sinks:
      - pattern-either:
          - pattern: Html.apply(...)
          - pattern: Ok(...).as(HTML)
          - pattern: Ok(...).as(ContentTypes.HTML)
          - patterns:
              - pattern: Ok(...).as($CTYPE)
              - metavariable-regex:
                  metavariable: $CTYPE
                  regex: '"[tT][eE][xX][tT]/[hH][tT][mM][lL]"'
          - patterns:
              - pattern: Ok(...).as($CTYPE)
              - pattern-not: Ok(...).as("...")
              - pattern-either:
                  - pattern-inside: |
                      def $FUNC(..., $URL: $T, ...) = $A {
                        ...
                      }
                  - pattern-inside: |
                      def $FUNC(..., $URL: $T, ...) = {
                        ...
                      }
    severity: WARNING
    languages:
      - scala

Examples

tainted-html-response.scala

package controllers

import play.api._
import play.api.mvc.{Action, Controller}
import play.twirl.api.Html;

class XssController extends Controller {

  def vulnerable1(value: String) = Action { implicit request: Request[AnyContent] =>
    // ruleid: tainted-html-response
    Ok(s"Hello $value !").as("text/html")
  }

  def vulnerable2(value: String) = Action.async { implicit request: Request[AnyContent] =>
    // ruleid: tainted-html-response
    Ok("Hello " + value + " !").as("tExT/HtML")
  }

  def vulnerable3(value: String, contentType: String) = Action { implicit request: Request[AnyContent] =>
    val bodyVals = request.body.asFormUrlEncoded
    val smth = bodyVals.get("username").head
    // ruleid: tainted-html-response
    Ok(s"Hello $smth !").as(contentType)
  }

  def vulnerable4(value: String) = Action.async(parse.json) { implicit request: Request[AnyContent] =>
    // ruleid: tainted-html-response
    Ok("Hello " + value + " !").as(ContentTypes.HTML)
  }

  def vulnerable5(value: String) = Action(parse.json) {
    // ruleid: tainted-html-response
    Ok(s"Hello $value !").as(HTML)
  }

  def vulnerable6(value:String) = Action { implicit request: Request[AnyContent] =>
    // ruleid: tainted-html-response
    Ok(views.html.xssHtml.render(Html.apply("Hello "+value+" !")))
  }
  
  def vulnerable7(value:String) = Action {
    // ruleid: tainted-html-response
    Ok(views.html.xssHtml.render(Html.apply("Hello "+value+" !")))
  }

  def safeJson(value: String) = Action.async { implicit request: Request[AnyContent] =>
    // ok: tainted-html-response
    Ok("Hello " + value + " !").as("text/json")
  }

  def safeTemplate(value:String) = Action {
    // ok: tainted-html-response
    Ok(views.html.template.render(value))
  }

  def variousSafe(value: String) = Action { implicit request: Request[AnyContent] =>
    // ok: tainted-html-response
    Ok("Hello "+value+" !")
    // ok: tainted-html-response
    Ok(s"Hello $value !").as("text/json")
    // ok: tainted-html-response
    Ok("<b>Hello !</b>").as("text/html")
    // ok: tainted-html-response
    Ok(views.html.xssHtml.render(Html.apply("<b>Hello !</b>")))

    val escapedValue = org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(value)
    // ok: tainted-html-response
    Ok("Hello " + escapedValue + " !")
    // ok: tainted-html-response
    Ok("Hello " + escapedValue + " !").as("text/html")

    val owaspEscapedValue = org.owasp.encoder.Encode.forHtml(value)
    // ok: tainted-html-response
    Ok("Hello " + owaspEscapedValue + " !")
    // ok: tainted-html-response
    Ok("Hello " + owaspEscapedValue + " !").as("text/html")
  }
}