javascript.jwt-simple.security.jwt-simple-noverify.jwt-simple-noverify

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Detected the decoding of a JWT token without a verify step. JWT tokens must be verified before use, otherwise the token's integrity is unknown. This means a malicious actor could forge a JWT token with any claims. Set 'verify' to true before using the token.

Run Locally

Run in CI

Defintion

rules:
  - id: jwt-simple-noverify
    message: Detected the decoding of a JWT token without a verify step. JWT tokens
      must be verified before use, otherwise the token's integrity is unknown.
      This means a malicious actor could forge a JWT token with any claims. Set
      'verify' to `true` before using the token.
    severity: ERROR
    metadata:
      owasp:
        - A05:2021 - Security Misconfiguration
        - A07:2021 - Identification and Authentication Failures
      cwe:
        - "CWE-287: Improper Authentication"
        - "CWE-345: Insufficient Verification of Data Authenticity"
        - "CWE-347: Improper Verification of Cryptographic Signature"
      category: security
      subcategory:
        - vuln
      technology:
        - jwt-simple
        - jwt
      confidence: HIGH
      likelihood: MEDIUM
      impact: HIGH
      references:
        - https://www.npmjs.com/package/jwt-simple
        - https://cwe.mitre.org/data/definitions/287
        - https://cwe.mitre.org/data/definitions/345
        - https://cwe.mitre.org/data/definitions/347
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cryptographic Issues
        - Improper Authentication
    languages:
      - javascript
      - typescript
    patterns:
      - pattern-inside: |
          $JWT = require('jwt-simple');
          ...
      - pattern: $JWT.decode($TOKEN, $SECRET, $NOVERIFY, ...)
      - metavariable-pattern:
          metavariable: $NOVERIFY
          patterns:
            - pattern-either:
                - pattern: |
                    true
                - pattern: |
                    "..."

Examples

jwt-simple-noverify.js

const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jwt-simple');
const mongoose = require('mongoose');
const mongoSanitize = require('express-mongo-sanitize');

const app = express();
app.use(express.json());
app.use(mongoSanitize());
const secretKey = process.env.JWT_SECRET;

// Sample MongoDB connection URI
const mongoURI = 'mongodb://localhost:27017/test';

// Connect to MongoDB using Mongoose
mongoose.connect(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true });
const db = mongoose.connection;

// Create a user schema
const userSchema = new mongoose.Schema({
  username: String,
  password: String
});

// Create a user model
const User = mongoose.model('User', userSchema);

// Route for user login
app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  try {
    // Find user by username
    const user = await User.findOne({ username });

    if (!user) {
      return res.status(401).json({ error: 'Authentication failed. User not found.' });
    }

    // Compare password with hashed password
    const isPasswordValid = await bcrypt.compare(password, user.password);

    if (!isPasswordValid) {
      return res.status(401).json({ error: 'Authentication failed. Invalid password.' });
    }

    // Issue JWT token
    const token = jwt.encode({ username }, secretKey,'HS256');
    res.json({ token });
  } catch (error) {
    console.error('Error occurred during login:', error);
    res.status(500).json({ error: 'Internal server error.' });
  }
});

// Route that requires authentication
app.get('/protectedRoute1', (req, res) => {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: 'Unauthorized. Token missing.' });
  }

  try {
    // ruleid: jwt-simple-noverify  
    const decoded = jwt.decode(token, secretKey, 'HS256');
    res.json({ message: `Hello ${decoded.username}` });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized. Invalid token.' });
  }
});

// Route that requires authentication
app.get('/protectedRoute2', (req, res) => {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: 'Unauthorized. Token missing.' });
  }

  try {
    // ruleid: jwt-simple-noverify   
    const decoded = jwt.decode(token, secretKey, true);
    res.json({ message: `Hello ${decoded.username}` });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized. Invalid token.' });
  }
});

// Route that requires authentication
app.get('/protectedRoute3', (req, res) => {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: 'Unauthorized. Token missing.' });
  }

  try {
    // ruleid: jwt-simple-noverify    
    const decoded = jwt.decode(token, secretKey, 'false');
    res.json({ message: `Hello ${decoded.username}` });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized. Invalid token.' });
  }
});

// Route that requires authentication
app.get('/protectedRoute4', (req, res) => {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: 'Unauthorized. Token missing.' });
  }

  try {
    // ok: jwt-simple-noverify   
    const decoded = jwt.decode(token, secretKey);
    res.json({ message: `Hello ${decoded.username}` });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized. Invalid token.' });
  }
});

// Route that requires authentication
app.get('/protectedRoute5', (req, res) => {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: 'Unauthorized. Token missing.' });
  }

  try {
    // ok: jwt-simple-noverify    
    const decoded = jwt.decode(token, secretKey, false);
    res.json({ message: `Hello ${decoded.username}` });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized. Invalid token.' });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));