T09 · Insecure Skill Coding Practices
- Location
scripts/jwt_decode.py:145- Finding
Unverified JWTs Are Misreported as Valid
- Content
View full analysis
Vulnerability Details
File Location:
scripts/jwt_decode.py:145-152, 231-243
Vulnerability Type: JWT validation without signature or trust-policy verification
Risk Level: HighVulnerable Code
python # Expiry status lines.append("") lines.append("=== TOKEN STATUS ===") if expiry["expired"] is not None: if expiry["expired"]: lines.append(f"Status: EXPIRED — {expiry['expires_in']}") else: lines.append(f"Status: VALID — expires in {expiry['expires_in']}") else: lines.append("Status: No expiration set")python expiry = check_expiry(decoded["payload"]) if args.format == "json": output = { "header": decoded["header"], "payload": decoded["payload"], "signature_present": decoded["signature"] is not None, "expiry": expiry, } print(json.dumps(output, indent=2, default=str)) else: print(format_text(decoded, expiry))Technical Analysis
The program Base64URL-decodes the JWT header and payload and evaluates attacker-controlled
expandnbfclaims. It does not cryptographically verify the signature, select a trusted verification key, restrict acceptable algorithms, or enforce trusted issuer and audience values.Despite the absence of authenticity verification, the text formatter reports a non-expired token as
Status: VALID. The skill documentation also describes the utility as able to “validate JWT tokens.” Signature presence is only reported as metadata and does not establish that the signature is correct.JWT claims are untrusted until the token signature and applicable trust policy have been verified. An attacker can construct a token containing arbitrary identity or authorization claims and a future expiration time. Such a token will be reported as valid even if its signature is forged, empty, or generated using an untrusted key.
Attack Path
- An attacker creates a JWT cont ...[truncated 1335 chars]
- Remediation
View remediation
Remediation Suggestions
- If the tool is intended only for inspection, replace
Status: VALIDwith explicit language such asStatus: NOT EXPIRED — SIGNATURE NOT VERIFIED. - Display a prominent warning in both text and JSON output that all decoded header and payload values are untrusted.
- Rename documentation and command descriptions from “validate” to “decode” or “inspect” unless cryptographic validation is implemented.
- Separate temporal status from authenticity status. For example, report
expiration_status,signature_status, andpolicy_statusindependently. - If validation is required, accept an explicitly trusted key or key set and cryptographically verify the JWT signature before declaring it valid.
- Enforce an explicit algorithm allowlist rather than trusting the token-controlled
algheader. Rejectnoneand unexpected algorithms. - Validate issuer, audience, expiration, not-before, and issued-at claims against caller-supplied policy. Apply an appropriate clock-skew allowance.
- Reject malformed claim types instead of performing comparisons directly against arbitrary decoded JSON values.
- Ensure JSON output includes an unmistakable field such as
"cryptographically_verified": falsewhen operating in decode-only mode. - Add tests proving that forged, unsigned, expired, not-yet-valid, wrong-issuer, wrong-audience, and disallowed-algorithm tokens are never labeled valid.
- If the tool is intended only for inspection, replace
