GH GambleHub

JWT: structure and vulnerabilities

1) What is JWT and where is it used

JWT is a compact self-contained claims container in the 'Base64Url (header) format. Base64Url(payload). Base64Url(signature)`.

Used for:
  • JWS (signed tokens - authenticity/integrity),
  • JWE (encrypted tokens - privacy),
  • OIDC/OAuth2 as access/ID tokens as well as service-to-service authentication.

Pros: autonomy, cachability, low overhead. Cons: risk of incorrect validation, complex recall cases.

2) JWT structure

2. 1 Header (JSON)

Minimum: algorithm and key identifier.

json
{ "alg": "ES256", "kid": "jwt-2025-10", "typ": "JWT" }

'alg ': signature/encryption algorithm (RS256/ES256/PS256/HS256, etc.).
'kid ': pointer to key (for JWKS rotation).
Optional key sources: 'jku', 'x5u' (see vulnerabilities § 6. 3).

2. 2 Payload (JSON)

Standardized stamps:
  • `iss` (issuer), `aud` (audience), `sub` (subject)
  • 'exp '(expiration time),' nbf '(not before),' iat '(issued)
  • 'jti '(token ID, revocable)
  • domain-stamps: 'scope/roles', 'tenant', 'kyc _ level', etc.

2. 3 Signature

JWS = `sign(base64url(header) + "." + base64url(payload), private_key)`

Verification: strictly corresponding public key and exactly the algorithm that the server expects.

3) Basic check invariants

1. The algorithm is fixed by the configuration of the resource server (allow-list), and is not trusted with the contents of the'header. alg`.
2. Check 'iss' and 'aud' for an exact match, 'exp/nbf' - taking into account the small 'clock _ skew' (± 30-60s).
3. Deny tokens without 'kid' only if there is a single key and no rotation; otherwise, demand 'kid'.
4. Do not trust any stamps without object-level authorization (BOLA-first).
5. Parsing - after crypto verification; basic size checks prior to decoding.

4) JWS vs JWE

JWS: signed but readable. Do not put in payload PII/secrets.
JWE: encrypts payload; integration is more difficult, the key model is critical.
In most APIs, JWS + prohibition on sensitive data in payload is enough.

5) Token life cycle

Access: short term (5-30 minutes).
Refresh: longer (7-30 days), rotate-on-use (one-time), keep the "black list" 'jti/sid'.
Revocation: lists' jti'with TTL, introspection for opaque tokens, abbreviation' exp'for incidents.

Key rotation: JWKS with overlap (old + new), see the article "Key rotation."

6) Frequent vulnerabilities and how to close them

6. 1'alg = none '/algorithm substitution

Bottom line: The server trusts the'alg 'field and accepts an unsigned token.
Protection: hard allow-list of algorithms on the server; reject'none 'and unexpected values.

6. 2 RS256→HS256 swap (symmetrization)

Bottom line: an attacker replaces' alg'with HS256 and uses the public key as an HMAC secret.
Protection: bind the key to the algorithm with configuration; do not mix symmetric/asymmetric providers in one'kid '.

6. 3 Key injection ('kid/jku/x5u')

Scenarios:
  • 'jku'points to an attacker-controlled JWKS (will slip its key).
  • 'x5u '/' x5c'abuse of external certificates.
  • 'kid'with/SQL path injection ('.. "/../privkey. pem"' or '"'OR 1 = 1 -- "').
Protection:
  • Ignore deleted'jku/x5u 'or filter by strict allow-list domains.
  • 'kid'should only be used as a key in the local directory (table/cache), without file paths/SQL concatenations.
  • JWKS load from trusted URLs, short TTL, signature/pinning channel.

6. 4 Weak secrets of HS256 (brute force)

Bottom line: HMAC secret is short/leaked → signature spoofing.
Protection: use asymmetry (RS/ES/PS) or secret length ≥ 256 bits, secrets - only in KMS.

6. 5 Missing/invalid stamps

No'aud '/' iss '/' exp '→ token is cross-serviceable or infinite.
Too long'exp '→ risk of compromise.
Protection: require full set of marks, 'exp' short, 'nbf '/' iat' validate with 'clock _ skew'.

6. 6 Replay and token theft

Essence: interception/repetition of a token (leak in logs, XSS, MitM without TLS).

Protection:
  • TLS везде, `Secure`+`HttpOnly` cookie, SameSite=Lax/Strict.
  • DPoP/PoP (binding a token to a client key) and/or mTLS for partners.
  • Short'exp ', refresh-rotation, device-binding.

6. 7 XSS/Storage Leaks

Bottom line: JWT storage in 'localStorage '/' sessionStorage' is → available to JS.
Protection: store access tokens in HttpOnly-cookie (if cookie model is possible) + strict CSP/Trusted Types.
For SPA without cookies - isolate the token in memory, live minimally, protect against XSS.

6. 8 CSRF

The bottom line: during cookie sessions, requests from a third-party site.
Protection: SameSite, anti-CSRF tokens (double submit), 'Origin/Referer' check, Fetch-Metadata filters.

6. 9 Oversize/size abuse

Gist: huge payload/headlines, DoS on parsing.
Protection: title/body size limits, early-reject 431/413, fixed set of stamps.

6. 10 Substitution 'typ '/' cty'

Essence: confusion of types ('typ: "JWT"'), nested JOSE objects.
Protection: ignore 'typ/cty' for security, rely on fixed algorithms and branding scheme.

7) Token storage and transfer

7. 1 Server APIs (machine-to-machine)

mTLS/HMAC, preferably asymmetry for JWT, channels through mesh.
Key store - KMS/HSM, scheduled rotation, overlapping JWKS.

7. 2 Browser clients

HttpOnly Secure Cookie для access/refresh; short TTL; update - via "silent refresh" with'SameSite = None'only under HTTPS.
Strict CSP, Trusted Types, protect against XSS; for SPA - if possible, do not store the token on disk.

8) JWKS, rotation and recall

JWKS is published by the authorizer; consumers cache for 5-15 minutes.
Rotation plan: add a new 'kid' → start them signing → after N days remove the old one from JWKS → purge.
Feedback: 'jti/sid' lists with TTL; in case of an incident, temporarily reduce 'exp' and force-logout (disable refresh).

9) Multi-tenant and data minimization

Include 'tenant '/' org' in the token only if necessary by architecture; otherwise, pull the attributes from the PDP by'sub '.
No PIIs; minimum set of stamps → less risk of leaks and correlation.

10) Practical validation checklist (resource server)

  • Parsim only after verification of signature and basic size limits.
  • 'alg' from configuration; reject unexpected ones.
  • Check 'iss' ∧ 'aud' ∧ 'exp' ∧ 'nbf' ∧ 'iat' (with 'clock _ skew').
  • Check'kid 'on local directory/JWKS (short TTL).
  • Filter/normalize external pointers ('jku/x5u' - allow-list only).
  • Limit stamp length/composition (scheme).
  • Apply Object Resource Authorization (BOLA-first).
  • Log 'kid', 'sub', 'aud', 'iss', 'jti', 'exp', 'tenant', 'trace _ id' (without PII).
  • Metrics of signature errors, delays, rotation audits.

11) Examples of secure policies (pseudo)

11. 1 Configuration of algorithm expectations

yaml jwt:
expected_issuer: "https://auth. example. com"
expected_audience: ["wallet-service"]
allowed_algs: ["ES256"] # fix the jwks_url: "https ://auth. example. com/.well-known/jwks. json"
jwks_cache_ttl: 600s clock_skew: 60s required_claims: ["iss","aud","sub","exp","iat"]

11. 2 Dropping remote 'jku/x5u'

yaml reject_untrusted_key_sources: true allowed_jku_hosts: ["auth. example. com"] # if absolutely necessary

11. 3 Sample Feedback List (Redis)

pseudo if redis. exists("revoke:jti:" + jti) then deny()
if now() > exp then deny()

12) Observability and incidence

Метрики: `jwt_verify_fail_total{reason}`, `jwt_expired_total`, `jwks_refresh_total`, доля `kid`.
Logs (structured): 'iss/aud/sub/kid/jti/exp/tenant/trace _ id', reason for failure.
Dashboards: "expiring soon," a surge in validation errors, distribution by region/client.
Alerts: growth of'verify _ fail' (signature/algorithm), JWKS errors, share of expired tokens.

13) Antipatterns

Trust'alg 'from token; support'none '.
Long-lived access tokens and no refresh rotation.
HS256 with a short secret/secret in ENV without KMS.
Accept'jku/x5u 'from any domain; dynamically load JWKS without allow-list.
Put PII/secrets in payload JWS.
Store tokens in 'localStorage' when XSS risks exist.
Suppress validation errors (return 200 s "soft error").
No BOLA checks and relying only on 'scope/role'.

14) Specifics of iGaming/Finance

Brands: 'kyc _ level', 'risk _ tier', 'tenant', strict 'aud'.
Short TTL for write operations (deposits/outputs), PoP/DPoP or mTLS for critical routes.
Regulatory audit: unchangeable logs of inputs/failures, storage of logs within the boundaries of the region.
Partners/PSP have separate keys/' aud ', tenant keys and separate JWKS.

15) Prod Readiness Checklist

  • Hard allow-list of algorithms; 'none' is not allowed.
  • 'iss/aud/exp/nbf/iat/jti' are checked; short 'exp'.
  • overlapped JWKS, short TTL cache; monitoring of 'kid' shares.
  • Refresh — rotate-on-use; 'jti/sid'lists with TTL; review playbook.
  • PoP/DPoP or mTLS on critical routes.
  • HttpOnly-cookies for browser, CSP/Trusted Types vs. XSS; CSRF protection.
  • No PII in payload; minimum set of marks.
  • Validation and failure metrics/logs; alerts JWKS/verify_fail.
  • Negative scenario tests: RS→HS swap, 'kid' -injections, 'jku' spoofing, oversize, clock-skew.

16) TL; DR

Fix the algorithm and keys on the server side, do not trust 'alg' from the token, demand 'iss/aud/exp/nbf/iat/jti'. Rotate keys through overlapping JWKS, keep tokens short-lived and refresh disposable. Store tokens securely (HttpOnly-cookie for the web), minimize stamps, do not put PII. Close 'jku/x5u/kid' vectors, avoid HS256 with weak secrets, add PoP/DPoP or mTLS on critical paths, and always do BOLA checks at the resource level.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Telegram
@Gamble_GC
Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.