Semmle 1.21
Skip to end of metadata
Go to start of metadata

Name: Uncontrolled data in SQL query

Description: Including user-supplied data in a SQL query without neutralizing special elements can make code vulnerable to SQL Injection.

ID: cpp/sql-injection

Kind: problem

Severity: error

Precision: high

Query: SqlTainted.ql
/**
 * @name Uncontrolled data in SQL query
 * @description Including user-supplied data in a SQL query without
 *              neutralizing special elements can make code vulnerable
 *              to SQL Injection.
 * @kind problem
 * @problem.severity error
 * @precision high
 * @id cpp/sql-injection
 * @tags security
 *       external/cwe/cwe-089
 */
import cpp
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.FunctionWithWrappers
import semmle.code.cpp.security.TaintTracking

class SQLLikeFunction extends FunctionWithWrappers {
  SQLLikeFunction() {
    sqlArgument(this.getName(), _)
  }

  override predicate interestingArg(int arg) {
    sqlArgument(this.getName(), arg)
  }
}

from SQLLikeFunction runSql,
     Expr taintedArg, Expr taintSource, string taintCause, string callChain
where runSql.outermostWrapperFunctionCall(taintedArg, callChain)
  and tainted(taintSource, taintedArg)
  and isUserInput(taintSource, taintCause)
select
  taintedArg,
  "This argument to a SQL query function is derived from $@ and then passed to " + callChain,
  taintSource, "user input (" + taintCause + ")"

The code passes user input as part of a SQL query without escaping special elements. It generates a SQL query using sprintf, with the user-supplied data directly passed as an argument to sprintf. This leaves the code vulnerable to attack by SQL Injection.

Recommendation

Use a library routine to escape characters in the user-supplied string before converting it to SQL.

Example

int main(int argc, char** argv) {
  char *userName = argv[2];
  
  // BAD
  char query1[1000] = {0};
  sprintf(query1, "SELECT UID FROM USERS where name = \"%s\"", userName);
  runSql(query1);
  
  // GOOD
  char userNameSql[1000] = {0};
  encodeSqlString(userNameSql, 1000, userName); 
  char query2[1000] = {0};
  sprintf(query2, "SELECT UID FROM USERS where name = \"%s\"", userNameSql);
  runSql(query2);
}

References