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

Author
unknown
Download Count*
License
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")
}
}
Short Link: https://sg.run/BG96