JWT User Input in Payload

LOW

Traces user-controlled input from Flask/Django request parameters into jwt.encode() payloads using taint analysis.

Rule Information

Language
Python
Category
JWT
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonjwtpyjwtdata-exposuretaint-analysisuser-inputflaskdjangorequest-dataCWE-522CWE-200OWASP-A02OWASP-A04
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-005 --project .
1
2
3
4
5
6
7
8
9
10
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

About This Rule

Understanding the vulnerability and how it is detected

This rule uses taint analysis to trace user-controlled data from web framework request objects into jwt.encode() calls. When user input flows directly into a JWT payload without validation, two things can go wrong: the user might submit sensitive data (passwords, personal information) that ends up base64-encoded in a readable token, or an attacker might inject claims that affect authorization decisions.

Unlike the other JWT rules that use pattern matching, this rule tracks actual data flow. It starts from Flask request methods (request.args.get, request.form.get) and Django request methods (request.GET.get, request.POST.get), follows the data through variable assignments, and flags when it reaches jwt.encode(). It uses standard propagation presets to track how data moves through the code.

This is the most precise JWT rule in the set -- it only fires when there's a proven data flow from user input to token creation. No data flow, no finding.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Sensitive Data Exposure via Token

If a user submits their password, SSN, or credit card number through a form, and that data flows into jwt.encode(), it ends up in a JWT that's visible to anyone who intercepts it. JWTs are not encrypted -- the payload is just base64-encoded JSON.

2

Claim Injection

If user input becomes a JWT claim without validation, an attacker could inject authorization-relevant claims. For example, if the "role" field comes from user input, the attacker can set it to "admin". The token will be validly signed because the server created it, but with attacker-controlled claims.

3

Token Size Attacks

Unsanitized user input in JWT payloads can make tokens arbitrarily large. Large tokens can cause issues with cookie size limits (4KB), header size limits in proxies and load balancers, and increased bandwidth usage.

How to Fix

Recommended remediation steps

  • 1Never pass raw user input directly into jwt.encode() -- validate it against your database or business logic first
  • 2Build JWT payloads from server-side data, not from request parameters -- look up the user by their input, then use the server's record of their ID and role
  • 3Whitelist which fields can appear in the JWT payload and reject anything else
  • 4Validate input types and lengths before including them in any token
  • 5Consider whether the data needs to be in the token at all -- can the consuming service look it up by user_id instead?

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule uses intra-procedural taint analysis (scope=local) to trace data from Flask request methods (request.args.get, request.form.get, request.GET.get, request.POST.get) to jwt.encode() as a sink. It uses standard propagation presets to track how tainted data flows through variable assignments. The flow must be within a single function -- cross-function flows require scope=global.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

OWASP Top 10
A02:2021 - Cryptographic Failures
OWASP Top 10
A04:2021 - Insecure Design
PCI DSS v4.0
Requirement 6.2.4 -- prevent injection and data exposure attacks
GDPR
Article 32 -- appropriate technical measures to protect personal data
NIST SP 800-53
SI-10: Information Input Validation

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about JWT User Input in Payload

This rule uses taint analysis -- it tracks where the data comes from, not just where it ends up. It starts at Flask/Django request methods, follows the data through variable assignments, and only flags when that user-controlled data actually reaches jwt.encode(). If jwt.encode() uses server-side data that doesn't come from user input, this rule won't flag it.
Currently it uses scope=local, which tracks data flow within a single function. If the Flask route calls a helper function that does the jwt.encode(), the flow won't be detected at local scope. Switch to scope=global for cross-function tracking, but note this requires the inter-procedural analysis engine.
Flask: request.args.get, request.form.get. Django: request.GET.get, request.POST.get. These cover query parameters and form data. To add more sources (request.json, request.cookies, request.headers), modify the from_sources list in the rule file.
Not always, but it requires care. A validated username that maps to a known user is fine -- as long as you look up the user server-side and use your own data for the payload (user.id, user.role). What's dangerous is taking raw input like request.args.get("data") and putting it directly into the token without validation.
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.
Yes. The rule file is plain Python. Fork it and add your custom input methods to from_sources (e.g., calls("request.json.get"), calls("request.cookies.get")), your encoding functions to to_sinks, or your validation functions to sanitized_by. You can version-control the modified rule alongside your app code.
The data exposure depends on what the user submits. If it's just a username, the risk is low. If it's a password or credit card number, the risk is high. Since the rule can't determine what data is in the input, it's classified as LOW to avoid alert fatigue. The finding still deserves review to confirm what data flows through.

New feature

Get these findings posted directly on your GitHub pull requests

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

See how it works