javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-path

profile photo of semgrepsemgrep
Author
3,077
Download Count*

Default session middleware settings: path not set. It indicates the path of the cookie; use it to compare against the request path. If this and domain match, then send the cookie in the request.

Run Locally

Run in CI

Defintion

rules:
  - id: express-cookie-session-no-path
    message: "Default session middleware settings: `path` not set. It indicates the
      path of the cookie; use it to compare against the request path. If this
      and domain match, then send the cookie in the request."
    severity: WARNING
    languages:
      - javascript
      - typescript
    metadata:
      cwe:
        - "CWE-522: Insufficiently Protected Credentials"
      owasp:
        - A02:2017 - Broken Authentication
        - A04:2021 - Insecure Design
      source-rule-url: https://expressjs.com/en/advanced/best-practice-security.html
      category: security
      technology:
        - express
      cwe2021-top25: true
      subcategory:
        - vuln
      likelihood: HIGH
      impact: LOW
      confidence: MEDIUM
      references:
        - https://owasp.org/Top10/A04_2021-Insecure_Design
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cryptographic Issues
    patterns:
      - pattern-either:
          - pattern-inside: |
              $SESSION = require('cookie-session');
              ...
          - pattern-inside: |
              $SESSION = require('express-session');
              ...
      - pattern: $SESSION(...)
      - pattern-not-inside: $SESSION(<... {cookie:{path:...}} ...>,...)
      - pattern-not-inside: |
          $OPTS = <... {cookie:{path:...}} ...>;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $COOKIE = <... {path:...} ...>;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $OPTS.cookie = <... {path:...} ...>;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $COOKIE.path = ...;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $OPTS.cookie.path = ...;
          ...
          $SESSION($OPTS,...);

Examples

express-cookie-settings.js

var session = require('express-session')
var express = require('express')
var app = express()

function test1() {
  var expiryDate = new Date(Date.now() + 60 * 60 * 1000) // 1 hour
  var opts = {
    keys: ['key1', 'key2'],
    cookie: {
      secure: true,
      httpOnly: true,
      domain: 'example.com',
      path: 'foo/bar',
      expires: expiryDate
    }
  }
  // ruleid: express-cookie-session-default-name
  app.use(session(opts))
}

function test2() {
  // ruleid: express-cookie-session-no-secure
  app.use(session(Object.assign({
    keys: ['key1', 'key2'],
    name: 'foo'
  }, {
    cookie: {
      httpOnly: true,
      domain: 'example.com',
      path: 'foo/bar',
      expires: new Date(Date.now() + 60 * 60 * 1000)
    }
  })))
}

function test3() {
  // ruleid: express-cookie-session-no-httponly
  app.use(session({
    keys: ['key1', 'key2'],
    name: 'foo',
    cookie: {
      secure: true,
      domain: 'example.com',
      path: 'foo/bar',
      expires: new Date(Date.now() + 60 * 60 * 1000)
    }
  }))
}

function test4() {
  var opts = {
    keys: ['key1', 'key2'],
    name: 'foo',
  }

  if (app.get('env') === 'production') {
    app.set('trust proxy', 1) // trust first proxy
    opts.cookie = {
      secure: true,
      httpOnly: true,
      path: 'foo/bar',
      expires: new Date(Date.now() + 60 * 60 * 1000)
    }
  }
  // ruleid: express-cookie-session-no-domain
  app.use(session(opts))
}

function test5() {
  var expiryDate = new Date(Date.now() + 60 * 60 * 1000) // 1 hour
  var opts = {
    keys: ['key1', 'key2'],
    name: 'foo',
    cookie: {
      secure: true,
      httpOnly: true
    }
  }

  if (app.get('env') === 'production') {
    app.set('trust proxy', 1) // trust first proxy
    opts.cookie.domain = 'example.com'
    opts.cookie.expires = expiryDate
  }

  // ruleid: express-cookie-session-no-path
  app.use(session(opts))
}

function test6() {
  var opts = {
    keys: ['key1', 'key2'],
    name: 'foo',
    cookie: {
      secure: true,
      httpOnly: true,
      domain: 'example.com',
      path: 'foo/bar'
    }
  }

  // ruleid: express-cookie-session-no-expires
  app.use(session(opts))
}

function okTest() {
  var expiryDate = new Date(Date.now() + 60 * 60 * 1000) // 1 hour
  var opts = {
    keys: ['key1', 'key2'],
    name: 'foo',
    cookie: {
      secure: true,
      httpOnly: true,
      domain: 'example.com',
      path: 'foo/bar',
      expires: expiryDate
    }
  }

  app.use(session(opts))
}