typescript.react.security.audit.react-jwt-in-localstorage.react-jwt-in-localstorage

profile photo of semgrepsemgrep
Author
4,056
Download Count*

Storing JWT tokens in localStorage known to be a bad practice, consider moving your tokens from localStorage to a HTTP cookie.

Run Locally

Run in CI

Defintion

rules:
  - id: react-jwt-in-localstorage
    message: Storing JWT tokens in localStorage known to be a bad practice, consider
      moving your tokens from localStorage to a HTTP cookie.
    metadata:
      cwe:
        - "CWE-922: Insecure Storage of Sensitive Information"
      references:
        - https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
      category: security
      owasp:
        - A01:2021 - Broken Access Control
      technology:
        - react
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Mishandled Sensitive Information
    languages:
      - typescript
      - javascript
    severity: INFO
    patterns:
      - pattern-inside: |
          import jwt_decode from "jwt-decode";
          ...
      - pattern-either:
          - pattern: |
              $DECODED = jwt_decode($TOKEN,...);
              ...
              localStorage.setItem($NAME, <... $TOKEN ...>);
          - pattern: |
              $DECODED = jwt_decode(...);
              ...
              localStorage.setItem($NAME, <... $DECODED ...>);

Examples

react-jwt-in-localstorage.jsx

import jwt_decode from "jwt-decode";
import { something } from "foobar";

export const testAuth1 = async () => {
  const { token } = await retrieveToken();
// ruleid: react-jwt-in-localstorage
  const decoded = jwt_decode(token);
  localStorage.setItem(TOKEN_PARAM, token);
};

export const testAuth2 = async () => {
  const { token } = await retrieveToken();
// ruleid: react-jwt-in-localstorage
  const decoded = jwt_decode(token);
  localStorage.setItem(EXPIRES_TOKEN, JSON.stringify(decoded.exp * 1000));
};

export const okTestAuth1 = async () => {
  const { token } = await retrieveToken();
// ok: react-jwt-in-localstorage
  const decoded = jwt_decode(token);
  something(EXPIRES_TOKEN, JSON.stringify(decoded.exp * 1000));
};

react-jwt-in-localstorage.tsx

import jwt_decode from "jwt-decode";
import { something } from "foobar";

export const testAuth1 = async (): Promise<void> => {
  const { token } = await retrieveToken();
// ruleid: react-jwt-in-localstorage
  const decoded = jwt_decode<any>(token);
  localStorage.setItem(TOKEN_PARAM, token);
};

export const testAuth2 = async (): Promise<void> => {
  const { token } = await retrieveToken();
// ruleid: react-jwt-in-localstorage
  const decoded = jwt_decode<any>(token);
  localStorage.setItem(EXPIRES_TOKEN, JSON.stringify(decoded.exp * 1000));
};

export const okTestAuth1 = async (): Promise<void> => {
  const { token } = await retrieveToken();
// ok: react-jwt-in-localstorage
  const decoded = jwt_decode<any>(token);
  something(EXPIRES_TOKEN, JSON.stringify(decoded.exp * 1000));
};