rules:
  - id: auth.jwt.weak-secret
    languages:
      - javascript
      - typescript
    severity: ERROR
    message: |
      JWT signing or verification uses a hard-coded secret. Anyone who reads
      the source (including via leaked GitHub commits) can forge valid tokens.

      Move the secret to an environment variable or secret manager, and ensure
      the value is at least 256 bits (32 ASCII characters) when using HMAC-based
      algorithms (HS256/HS384/HS512).

      Real-world incident: 24,008 unique secrets were found in MCP config files
      and 3.2% of Claude Code commits leaked secrets in GitGuardian's 2026 report.
    # Scoped to the `jsonwebtoken` alias `jwt` to avoid matching jose's
    # low-level `sig.sign(key, options)` and similar generic patterns
    # that were the FP class in real-world validation.
    pattern-either:
      - patterns:
          - pattern-either:
              - pattern: 'jwt.sign($PAYLOAD, $SECRET)'
              - pattern: 'jwt.sign($PAYLOAD, $SECRET, ...)'
              - pattern: 'jwt.verify($TOKEN, $SECRET)'
              - pattern: 'jwt.verify($TOKEN, $SECRET, ...)'
          - metavariable-regex:
              metavariable: $SECRET
              regex: ^(["'])(?:[a-zA-Z0-9!._-]{1,20}|secret|password|changeme|jwt[-_]?secret|my[-_]?secret)\1$
      # Destructured import: `import { sign, verify } from 'jsonwebtoken'`.
      # Scoped to the import so bare sign()/verify() from other libraries are
      # not matched.
      - patterns:
          - pattern-inside: |
              import { ... } from 'jsonwebtoken'
              ...
          - pattern-either:
              - pattern: 'sign($PAYLOAD, $SECRET)'
              - pattern: 'sign($PAYLOAD, $SECRET, ...)'
              - pattern: 'verify($TOKEN, $SECRET)'
              - pattern: 'verify($TOKEN, $SECRET, ...)'
          - metavariable-regex:
              metavariable: $SECRET
              regex: ^(["'])(?:[a-zA-Z0-9!._-]{1,20}|secret|password|changeme|jwt[-_]?secret|my[-_]?secret)\1$
    metadata:
      oauthlint-rule-id: AUTH-JWT-002
      oauthlint-doc-url: https://oauthlint.dev/rules/jwt-weak-secret
      category: security
      cwe: CWE-798
      owasp: API2:2023
      llm-prevalence: HIGH
      technology:
        - jsonwebtoken
      references:
        - https://datatracker.ietf.org/doc/html/rfc7518#section-3.2
        - https://cwe.mitre.org/data/definitions/798.html
