E11084: hardcoded JWT token detected
What went wrong
A string literal matching the JWT (JSON Web Token) three-part structure (header.payload.signature) was found in source code. JWTs always begin with "eyJ" (base64url-encoded JSON object starting with "{") and contain two dots separating the three segments.
Hardcoded JWT tokens in source code are a security vulnerability because they typically contain authentication claims, session data, or API access grants that should remain confidential and short-lived.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 704 (How does EK9 detect hardcoded secrets at compile time?)
Rationale
JWTs are designed to be ephemeral — they carry expiration claims and are meant to be generated per-session or per-request. A hardcoded JWT in source code is always wrong: either it's expired (useless dead code) or it's still valid (leaked credential).
Even expired JWTs reveal information: the issuer, audience, claims structure, and signing algorithm. Attackers use this to forge new tokens or identify the authentication infrastructure.
How to fix it
Generate JWTs dynamically at runtime (from your authentication service, for the claims of the user) rather than hardcoding them. If you need a token for development, load it from an environment variable:
secret <- EnvVars().sensitiveGet("SESSION_TOKEN") if secret? configureService(secret)
For integration tests, use a local token-issuing service or generate tokens in your test setup code.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E11084: hardcoded JWT token detected
#!ek9 defines module error.e11084.bad defines function <?- Standard JWT token detected — eyJ header.payload.signature format. -?> testStandardJwt() token <- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" stdout <- Stdout() stdout.println(token) <?- Another JWT with different claims. -?> testAnotherJwt() authHeader <- "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXVkIjoiYXBwIn0.signature_part_here" stdout <- Stdout() stdout.println(authHeader)
Fixed: Obtain the token at run time as a Sensitive
#!ek9 defines module error.e11084.good defines function configureService() -> token as Sensitive stdout <- Stdout() stdout.println($(token?)) demo() secret <- EnvVars().sensitiveGet("SESSION_TOKEN") if secret? configureService(secret)
Questions and answers
These Q&A entries show E11084 and its fix: