go.lang.security.audit.sqli.gosql-sqli.gosql-sqli

profile photo of semgrepsemgrep
Author
161
Download Count*

Detected string concatenation with a non-literal variable in a "database/sql" Go SQL statement. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, use parameterized queries or prepared statements instead. You can use prepared statements with the 'Prepare' and 'PrepareContext' calls.

Run Locally

Run in CI

Defintion

rules:
  - id: gosql-sqli
    patterns:
      - pattern-either:
          - patterns:
              - pattern: $DB.$METHOD(...,$QUERY,...)
              - pattern-either:
                  - pattern-inside: |
                      $QUERY = $X + $Y
                      ...
                  - pattern-inside: |
                      $QUERY += $X
                      ...
                  - pattern-inside: |
                      $QUERY = fmt.Sprintf("...", $PARAM1, ...)
                      ...
              - pattern-not-inside: |
                  $QUERY += "..."
                  ...
              - pattern-not-inside: |
                  $QUERY = "..." + "..."
                  ...
          - pattern: $DB.$METHOD(..., $X + $Y, ...)
          - pattern: $DB.$METHOD(..., fmt.Sprintf("...", $PARAM1, ...), ...)
      - pattern-either:
          - pattern-inside: |
              $DB, ... = sql.Open(...)
              ...
          - pattern-inside: |
              func $FUNCNAME(..., $DB *sql.DB, ...) {
                ...
              }
      - pattern-not: $DB.$METHOD(..., "..." + "...", ...)
      - metavariable-regex:
          metavariable: $METHOD
          regex: ^(Exec|ExecContent|Query|QueryContext|QueryRow|QueryRowContext)$
    languages:
      - go
    message: Detected string concatenation with a non-literal variable in a
      "database/sql" Go SQL statement. This could lead to SQL injection if the
      variable is user-controlled and not properly sanitized. In order to
      prevent SQL injection, use parameterized queries or prepared statements
      instead. You can use prepared statements with the 'Prepare' and
      'PrepareContext' calls.
    metadata:
      cwe:
        - "CWE-89: Improper Neutralization of Special Elements used in an SQL
          Command ('SQL Injection')"
      references:
        - https://golang.org/pkg/database/sql/
      category: security
      technology:
        - go
      confidence: LOW
      owasp:
        - A01:2017 - Injection
        - A03:2021 - Injection
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - vuln
      likelihood: LOW
      impact: HIGH
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - SQL Injection
    severity: ERROR

Examples

gosql-sqli.go

package main

import "database/sql"
import "fmt"

func bad1() {
    db, err := sql.Open("mysql", "theUser:thePassword@/theDbName")
    if err != nil {
        panic(err)
    }
    query = "SELECT name FROM users WHERE age=" + req.FormValue("age")
    // ruleid: gosql-sqli
    db.Query(query)
}

func bad2(db *sql.DB) {
    query = "SELECT name FROM users WHERE age="
    query += req.FormValue("age")
    // ruleid: gosql-sqli
    db.QueryRow(query)
}

func bad3(db *sql.DB) {
    query = fmt.Sprintf("SELECT * FROM users WHERE email='%s';", email)
    // ruleid: gosql-sqli
    db.Exec(query)
}

func bad4(db *sql.DB) {
    // ruleid: gosql-sqli
    db.Exec("SELECT name FROM users WHERE age=" + req.FormValue("age"))
}

func bad5(db *sql.DB) {
    // ruleid: gosql-sqli
    db.Exec(fmt.Sprintf("SELECT * FROM users WHERE email='%s';", email))
}

func ok1(db *sql.DB) {
    query = fmt.Sprintf("SELECT * FROM users WHERE email=hello;")
    // ok: gosql-sqli
    db.Exec(query)
}

func ok2(db *sql.DB) {
    query = "SELECT name FROM users WHERE age=" + "3"
    // ok: gosql-sqli
    db.Query(query)
}

func ok3(db *sql.DB) {
    query = "SELECT name FROM users WHERE age="
    query += "3"
    // ok: gosql-sqli
    db.Query(query)
}

func ok4(db *sql.DB) {
    // ok: gosql-sqli
    db.Exec("INSERT INTO users(name, email) VALUES($1, $2)",
  "Jon Calhoun", "jon@calhoun.io")
}

func ok5(db *sql.DB) {
    // ok: gosql-sqli
    db.Exec("SELECT name FROM users WHERE age=" + "3")
}

func ok6(db *sql.DB) {
    // ok: gosql-sqli
    db.Exec(fmt.Sprintf("SELECT * FROM users WHERE email=hello;"))
}