javascript.lang.security.audit.sqli.node-knex-sqli.node-knex-sqli

profile photo of returntocorpreturntocorp
Author
unknown
Download Count*

Detected SQL statement that is tainted by $REQ object. This could lead to SQL injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, it is recommended to use parameterized queries or prepared statements. An example of parameterized queries like so: knex.raw('SELECT $1 from table', [userinput]) can help prevent SQLi.

Run Locally

Run in CI

Defintion

rules:
  - id: node-knex-sqli
    message: "Detected SQL statement that is tainted by `$REQ` object. This could
      lead to SQL injection if the variable is user-controlled and not properly
      sanitized. In order to prevent SQL injection, it is recommended to use
      parameterized queries or prepared statements. An example of parameterized
      queries like so: `knex.raw('SELECT $1 from table', [userinput])` can help
      prevent SQLi."
    metadata:
      confidence: MEDIUM
      references:
        - https://knexjs.org/#Builder-fromRaw
        - https://knexjs.org/#Builder-whereRaw
        - https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
      category: security
      owasp:
        - A01:2017 - Injection
        - A03:2021 - Injection
      cwe:
        - "CWE-89: Improper Neutralization of Special Elements used in an SQL
          Command ('SQL Injection')"
      technology:
        - express
        - nodejs
        - knex
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - vuln
      likelihood: HIGH
      impact: MEDIUM
    languages:
      - javascript
      - typescript
    severity: WARNING
    mode: taint
    pattern-sources:
      - patterns:
          - pattern-either:
              - pattern-inside: function ... ($REQ, $RES) {...}
              - pattern-inside: function ... ($REQ, $RES, $NEXT) {...}
              - patterns:
                  - pattern-either:
                      - pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES) {...})
                      - pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, $NEXT) {...})
                  - metavariable-regex:
                      metavariable: $METHOD
                      regex: ^(get|post|put|head|delete|options)
          - pattern-either:
              - pattern: $REQ.query
              - pattern: $REQ.body
              - pattern: $REQ.params
              - pattern: $REQ.cookies
              - pattern: $REQ.headers
              - pattern: $REQ.files.$ANYTHING.data.toString('utf8')
              - pattern: $REQ.files.$ANYTHING['data'].toString('utf8')
      - patterns:
          - pattern-either:
              - pattern-inside: |
                  ({ $REQ }: Request,$RES: Response, $NEXT: NextFunction) =>
                  {...}
              - pattern-inside: |
                  ({ $REQ }: Request,$RES: Response) => {...}
          - focus-metavariable: $REQ
          - pattern-either:
              - pattern: params
              - pattern: query
              - pattern: cookies
              - pattern: headers
              - pattern: body
              - pattern: files.$ANYTHING.data.toString('utf8')
              - pattern: files.$ANYTHING['data'].toString('utf8')
    pattern-sinks:
      - patterns:
          - focus-metavariable: $QUERY
          - pattern-either:
              - pattern-inside: $KNEX.fromRaw($QUERY, ...)
              - pattern-inside: $KNEX.whereRaw($QUERY, ...)
              - pattern-inside: $KNEX.raw($QUERY, ...)
          - pattern-either:
              - pattern-inside: |
                  require('knex')
                  ...
              - pattern-inside: |
                  import 'knex'
                  ...
    pattern-sanitizers:
      - patterns:
          - pattern: parseInt(...)

Examples

node-knex-sqli.js

import knex from "knex";
import Knex from "knex";

exports.handler = async (req,res,next) => {
  const connection = knex({
    client: "mysql",
    connection: {
      host: process.env.DB_HOST,
      port: Number(process.env.DB_PORT || "3306"),
      user: process.env.DB_USER,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_DATABASE,
    },
  });

  // ruleid: node-knex-sqli
  await connection.raw(`
    INSERT INTO  (id, character, cartoon, link)
    VALUES(
        '${req.query.id}', 
        '${req.body.character}',
        '${req.query.cartoon}', 
        '${req.foo.link}'
    )
    `);

  // ok: node-knex-sqli
  await connection.raw('SELECT * FROM foobar');
};