JWT Hardcoded Secret

HIGH

Finds jwt.encode() calls where the signing secret is a hardcoded string instead of a runtime configuration value.

Rule Information

Language
Python
Category
JWT
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonjwtpyjwthardcoded-secretcredentialstoken-signingauthenticationCWE-798CWE-522OWASP-A02
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-JWT-SEC-001 --project .
1
2
3
4
5
6
7
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

About This Rule

Understanding the vulnerability and how it is detected

This rule detects jwt.encode() calls in your codebase where the signing secret might be hardcoded. A hardcoded JWT secret means anyone who reads your source code -- a contractor, an ex-employee, anyone with access to your Git history -- can forge valid tokens for any user. It also means you can't rotate the secret without redeploying every service that uses it.

The rule works by matching all jwt.encode() calls through type-aware resolution of the PyJWT library. It currently operates as an audit-level rule, meaning it flags every jwt.encode() call for manual review. This is because the engine cannot yet distinguish between a string literal argument (hardcoded) and a variable reference (potentially safe). Future versions will add an is_literal() qualifier to filter only calls where the secret argument is a string literal.

In practice, the fix is simple: move the secret to an environment variable, a secrets manager, or a configuration file that isn't checked into version control. For distributed systems, consider asymmetric signing (RS256/ES256) where the private key never leaves the signing service.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Token Forgery

Anyone with the secret can create valid JWTs. An attacker who finds the secret in your Git history, a Docker image layer, or a leaked backup can issue tokens with any claims -- admin roles, any user ID, unlimited expiration.

2

No Secret Rotation

Hardcoded secrets can't be rotated without a code change and redeployment. If the secret is compromised, you need to deploy new code to every service. With an environment variable or secrets manager, rotation is an ops task.

3

Credential Leakage via Source Code

Source code gets shared -- open source, contractor handoffs, CI logs, error messages. A secret in code is a secret waiting to leak. Environment variables and secrets managers keep credentials out of the codebase entirely.

4

Compliance Violations

PCI DSS, SOC 2, and ISO 27001 all prohibit hardcoded credentials. Auditors specifically look for secrets in source code. This finding will fail a compliance review.

How to Fix

Recommended remediation steps

  • 1Move JWT signing secrets to environment variables or a secrets manager like AWS Secrets Manager, HashiCorp Vault, or GCP Secret Manager
  • 2Use asymmetric algorithms (RS256, ES256) for distributed systems so the signing key never leaves the auth service
  • 3Rotate secrets periodically and ensure your architecture supports rotation without downtime
  • 4Add pre-commit hooks or CI checks to prevent secrets from being committed to version control
  • 5Never log or include JWT secrets in error messages, stack traces, or debug output

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule matches all jwt.encode() calls resolved through the PyJWT library using QueryType-based type inference. It identifies the jwt module by its fully qualified name and matches the encode method. Currently operates as an audit rule that flags all jwt.encode() calls for review.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-798 ranked #18 in 2023 Most Dangerous Software Weaknesses
OWASP Top 10
A02:2021 - Cryptographic Failures
PCI DSS v4.0
Requirement 6.2.4.2 -- do not hard-code passwords/keys in source code
SOC 2
CC6.1 -- logical and physical access controls for credentials
NIST SP 800-53
IA-5: Authenticator Management

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about JWT Hardcoded Secret

This rule currently operates at audit level -- it flags all jwt.encode() calls for review because the engine can't yet distinguish between a hardcoded string like "my_secret" and a variable like SECRET that loads from os.environ. If your secret comes from an environment variable or secrets manager, the finding is a false positive you can safely dismiss. Future engine updates will add literal detection to eliminate these false positives automatically.
It depends on your architecture. HS256 (symmetric) uses the same secret for signing and verification -- simpler, but every service that verifies tokens needs the secret. RS256 (asymmetric) uses a private key to sign and a public key to verify -- the private key stays on the auth server, and any service can verify with just the public key. For microservices, RS256 is usually the better choice because it reduces the blast radius of a key compromise.
Run: pathfinder ci --ruleset python/jwt --project . It outputs SARIF, JSON, or CSV. On GitHub, it posts inline review comments directly on pull requests pointing to the exact lines. No dashboard needed.
Replace the hardcoded string with os.environ["JWT_SECRET_KEY"]. Set the environment variable in your deployment config (Docker, Kubernetes secrets, .env file that's gitignored). This takes about two minutes and fixes the vulnerability permanently.
Length matters, but location matters more. A 256-bit random secret is cryptographically strong -- but if it's hardcoded in your source code, it's only as secure as your Git access controls. Move it to an environment variable. Then yes, generate it with python -c "import secrets; print(secrets.token_hex(32))" and you're good.
Yes. The QueryType matcher resolves jwt.encode() calls regardless of which file they appear in. If you import jwt in one file and call jwt.encode() in another, the rule still detects it.

New feature

Get these findings posted directly on your GitHub pull requests

The JWT Hardcoded Secret rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works