javascript.express.security.express-insecure-template-usage.express-insecure-template-usage

profile photo of semgrepsemgrep
Author
unknown
Download Count*

User data from $REQ is being compiled into the template, which can lead to a Server Side Template Injection (SSTI) vulnerability.

Run Locally

Run in CI

Defintion

rules:
  - id: express-insecure-template-usage
    message: User data from `$REQ` is being compiled into the template, which can
      lead to a Server Side Template Injection (SSTI) vulnerability.
    options:
      interfile: true
    metadata:
      interfile: true
      category: security
      cwe:
        - "CWE-1336: Improper Neutralization of Special Elements Used in a
          Template Engine"
      owasp:
        - A03:2021 - Injection
        - A01:2017 - Injection
      references:
        - https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html
      technology:
        - javascript
        - typescript
        - express
        - pug
        - jade
        - dot
        - ejs
        - nunjucks
        - lodash
        - handlbars
        - mustache
        - hogan.js
        - eta
        - squirrelly
      source_rule_url:
        - https://github.com/github/codeql/blob/2ba2642c7ab29b9eedef33bcc2b8cd1d203d0c10/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/template-sinks.js
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: MEDIUM
      confidence: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    languages:
      - javascript
      - typescript
    severity: WARNING
    mode: taint
    pattern-propagators:
      - pattern: $MODEL.$FIND($E).then((...,$S,...)=>{...})
        from: $E
        to: $S
    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
      - 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-sinks:
      - pattern-either:
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      $PUG = require('pug')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'pug'
                      ...
                  - pattern-inside: |
                      $PUG = require('jade')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'jade'
                      ...
              - pattern-either:
                  - pattern: $PUG.compile(...)
                  - pattern: $PUG.compileClient(...)
                  - pattern: $PUG.compileClientWithDependenciesTracked(...)
                  - pattern: $PUG.render(...)
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      $PUG = require('dot')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'dot'
                      ...
              - pattern-either:
                  - pattern: $PUG.template(...)
                  - pattern: $PUG.compile(...)
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      $PUG = require('ejs')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'ejs'
                      ...
              - pattern-either:
                  - pattern: $PUG.render(...)
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      $PUG = require('nunjucks')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'nunjucks'
                      ...
              - pattern-either:
                  - pattern: $PUG.renderString(...)
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      $PUG = require('lodash')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'lodash'
                      ...
              - pattern-either:
                  - pattern: $PUG.template(...)
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      $PUG = require('mustache')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'mustache'
                      ...
                  - pattern-inside: |
                      $PUG = require('eta')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'eta'
                      ...
                  - pattern-inside: |
                      $PUG = require('squirrelly')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'squirrelly'
                      ...
              - pattern-either:
                  - pattern: $PUG.render(...)
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      $PUG = require('hogan.js')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'hogan.js'
                      ...
                  - pattern-inside: |
                      $PUG = require('handlebars')
                      ...
                  - pattern-inside: |
                      import * as $PUG from 'handlebars'
                      ...
              - pattern-either:
                  - pattern: $PUG.compile(...)

Examples

express-insecure-template-usage.jsx

import express from 'express';
import * as pug from 'pug';
import * as jade from 'jade';
import * as dot from 'dot';
import * as ejs from 'ejs';
import * as nunjucks from 'nunjucks';
import * as lodash from 'lodash';
import * as handlebars from 'handlebars';
import * as mustache from 'mustache';
const Hogan = require("hogan.js");
import * as Eta from 'eta';
import * as Sqrl from 'squirrelly'

var app = express();

app.get('/', function(req, res) {
    let tainted = req.query.id;
    // ruleid: express-insecure-template-usage
    pug.compile(tainted); 
    // ruleid: express-insecure-template-usage
    pug.render(tainted); 
    // ruleid: express-insecure-template-usage
    jade.compile(tainted);
    // ruleid: express-insecure-template-usage
    jade.render(tainted);
     // ruleid: express-insecure-template-usage
    dot.template(tainted); 
    // ruleid: express-insecure-template-usage
    ejs.render(tainted); 
    // ruleid: express-insecure-template-usage
    nunjucks.renderString(tainted); 
    // ruleid: express-insecure-template-usage
    lodash.template(tainted); 
    // ruleid: express-insecure-template-usage
    dot.compile(tainted); 
    // ruleid: express-insecure-template-usage
    handlebars.compile(req.query.id); 
    // ruleid: express-insecure-template-usage
    mustache.render(req.body._); 
    // ruleid: express-insecure-template-usage
    Hogan.compile(tainted); 
    // ruleid: express-insecure-template-usage
    Eta.render(tainted); 
    // ruleid: express-insecure-template-usage
    Sqrl.render(tainted); 
});