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

profile photo of semgrepsemgrep
Author
3,077
Download Count*

Default session middleware settings: domain not set. It indicates the domain of the cookie; use it to compare against the domain of the server in which the URL is being requested. If they match, then check the path attribute next.

Run Locally

Run in CI

Defintion

rules:
  - id: express-cookie-session-no-domain
    message: "Default session middleware settings: `domain` not set. It indicates
      the domain of the cookie; use it to compare against the domain of the
      server in which the URL is being requested. If they match, then check the
      path attribute next."
    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:{domain:...}} ...>,...)
      - pattern-not-inside: |
          $OPTS = <... {cookie:{domain:...}} ...>;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $COOKIE = <... {domain:...} ...>;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $OPTS.cookie = <... {domain:...} ...>;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $COOKIE.domain = ...;
          ...
          $SESSION($OPTS,...);
      - pattern-not-inside: |
          $OPTS = ...;
          ...
          $OPTS.cookie.domain = ...;
          ...
          $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))
}