scala.play.security.tainted-slick-sqli.tainted-slick-sqli

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Detected a tainted SQL statement. This could lead to SQL injection if variables in the SQL statement are not properly sanitized. Avoid using using user input for generating SQL strings.

Run Locally

Run in CI

Defintion

rules:
  - id: tainted-slick-sqli
    mode: taint
    metadata:
      references:
        - https://scala-slick.org/doc/3.3.3/sql.html#splicing-literal-values
        - https://scala-slick.org/doc/3.2.0/sql-to-slick.html#non-optimal-sql-code
      category: security
      cwe:
        - "CWE-89: Improper Neutralization of Special Elements used in an SQL
          Command ('SQL Injection')"
      owasp:
        - A01:2017 - Injection
        - A03:2021 - Injection
      technology:
        - scala
        - slick
        - play
      confidence: HIGH
      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:
        - SQL Injection
    message: Detected a tainted SQL statement. This could lead to SQL injection if
      variables in the SQL statement are not properly sanitized. Avoid using
      using user input for generating SQL strings.
    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-sinks:
      - patterns:
          - pattern-either:
              - pattern: $MODEL.overrideSql(...)
              - pattern: sql"..."
          - pattern-inside: |
              import slick.$DEPS
              ...
    severity: ERROR
    languages:
      - scala

Examples

tainted-slick-sqli.scala

package controllers

import play.api.mvc._
import javax.inject._
import slick.jdbc.H2Profile.api._
import models.UserModel

@Singleton
class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController{
  val db = Database.forConfig("h2mem1")

  def oneAction() = Action { implicit request: Request[AnyContent] =>
    val bodyVals = request.body.asFormUrlEncoded
    val smth = bodyVals.get("username").head
    // ruleid: tainted-slick-sqli
    val action = sql"select ID, NAME, AGE from #$smth".as[(Int,String,Int)]
    db.run(action)
    Ok("ok")
  }

  def twoAction(name: String) = Action {
    val people = TableQuery[People]

    // ruleid: tainted-slick-sqli
    people.map(p => (p.id,p.name,p.age)).result.overrideSql(s"SELECT id, name, age FROM Person WHERE $name")

    Ok("ok")
  }

  def threeAction(name: String) = Action.async(parse.json) {
    val people = TableQuery[People]

    // ruleid: tainted-slick-sqli
    people.map(p => (p.id,p.name,p.age)).result.overrideSql(s"SELECT id, name, age FROM Person WHERE $name")

    Ok("ok")
  }

  def helloWorldPage() = Action { implicit request: Request[AnyContent] =>
    // ok: tainted-slick-sqli
    Ok(views.html.helloWorld())
  }

  def okAction1() = Action { implicit request: Request[AnyContent] =>
    val smth = "hardcoded_value"
    // ok: tainted-slick-sqli
    val action = sql"select ID, NAME, AGE from #$smth".as[(Int,String,Int)]
    db.run(action)
    Ok("ok")
  }

  def okAction2(name: String) = Action { implicit request: Request[AnyContent] =>
    val people = TableQuery[People]

    people.map(p => (p.id,p.name,p.age))
      .result
      // ok: tainted-slick-sqli
      .overrideSql(s"SELECT id, name, age FROM Person WHERE name = 'FooBar'")

    Ok("ok")
  }

}