javascript.express.security.audit.express-jwt-not-revoked.express-jwt-not-revoked

profile photo of semgrepsemgrep
Author
3,077
Download Count*

No token revoking configured for express-jwt. A leaked token could still be used and unable to be revoked. Consider using function as the isRevoked option.

Run Locally

Run in CI

Defintion

rules:
  - id: express-jwt-not-revoked
    message: No token revoking configured for `express-jwt`. A leaked token could
      still be used and unable to be revoked. Consider using function as the
      `isRevoked` option.
    metadata:
      cwe:
        - "CWE-522: Insufficiently Protected Credentials"
      owasp:
        - A02:2017 - Broken Authentication
        - A04:2021 - Insecure Design
      source-rule-url: https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/expirejwt.md
      asvs:
        section: "V3: Session Management Verification Requirements"
        control_id: 3.5.3 Insecue Stateless Session Tokens
        control_url: https://github.com/OWASP/ASVS/blob/master/4.0/en/0x12-V3-Session-management.md#v35-token-based-session-management
        version: "4"
      category: security
      technology:
        - express
      cwe2021-top25: true
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: MEDIUM
      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
    languages:
      - javascript
      - typescript
    severity: WARNING
    patterns:
      - pattern-inside: |
          $JWT = require('express-jwt');
          ...
      - pattern: $JWT(...)
      - pattern-not-inside: $JWT(<... {isRevoked:...} ...>,...)
      - pattern-not-inside: |-
          $OPTS = <... {isRevoked:...} ...>;
          ...
          $JWT($OPTS,...);

Examples

express-jwt-not-revoked.js

var jwt = require('express-jwt');
var blacklist = require('express-jwt-blacklist');

// ruleid: express-jwt-not-revoked
app.get('/ok-protected', jwt({ secret: process.env.SECRET }), function(req, res) {
    if (!req.user.admin) return res.sendStatus(401);
    res.sendStatus(200);
});

let configSecret = config.get('secret')
const opts = Object.assign({issuer: 'http://issuer'}, {secret: configSecret})
// ruleid: express-jwt-not-revoked
app.get('/ok-protected', jwt(opts), function(req, res) {
    if (!req.user.admin) return res.sendStatus(401);
    res.sendStatus(200);
});

// ok: express-jwt-not-revoked
app.get('/ok-protected', jwt({ secret: process.env.SECRET, isRevoked: blacklist.isRevoked }), function(req, res) {
    if (!req.user.admin) return res.sendStatus(401);
    res.sendStatus(200);
});

// ok: express-jwt-not-revoked
let configSecret = config.get('secret')
const opts = Object.assign({issuer: 'http://issuer'}, {isRevoked: blacklist.isRevoked})

app.get('/ok-protected', jwt(opts), function(req, res) {
    if (!req.user.admin) return res.sendStatus(401);
    res.sendStatus(200);
});