v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
HIGH AI PREVALENCE: HIGH auth.rust.jwt.hardcoded-secret

A JWT HMAC signing/verification key is hardcoded as a literal.

Why AI tools produce this: AI coding tools generate this anti-pattern by default, it appears in a large share of AI-written auth code.

Why this matters

It is passed directly to jsonwebtoken's EncodingKey::from_secret / DecodingKey::from_secret. Anyone who can read the source or git history can forge or tamper with tokens, which is a complete authentication bypass.

Load the secret at runtime from the environment or a secret manager instead, e.g. let key = std::env::var("JWT_SECRET")?; followed by EncodingKey::from_secret(key.as_bytes()). Never commit signing keys to source control.

VULNERABLE
vulnerable.rs
use jsonwebtoken::{DecodingKey, EncodingKey};

fn signing_key() -> EncodingKey {
    // ruleid: auth.rust.jwt.hardcoded-secret
    EncodingKey::from_secret(b"supersecret")
}

fn verification_key() -> DecodingKey {
    // ruleid: auth.rust.jwt.hardcoded-secret
    DecodingKey::from_secret(b"supersecret")
}

fn signing_key_str() -> EncodingKey {
    // ruleid: auth.rust.jwt.hardcoded-secret
    EncodingKey::from_secret("hardcoded-literal".as_ref())
}
SAFE
safe.rs
use jsonwebtoken::EncodingKey;

// ok: auth.rust.jwt.hardcoded-secret -- key comes from a variable, not a literal
fn signing_key_from_var(secret: &str) -> EncodingKey {
    EncodingKey::from_secret(secret.as_bytes())
}

// ok: auth.rust.jwt.hardcoded-secret -- key loaded from the environment at runtime
fn signing_key_from_env() -> EncodingKey {
    let secret = std::env::var("JWT_SECRET").unwrap();
    EncodingKey::from_secret(secret.as_bytes())
}

// ok: auth.rust.jwt.hardcoded-secret -- inline env read, still not a literal
fn signing_key_inline_env() -> EncodingKey {
    EncodingKey::from_secret(std::env::var("JWT_SECRET").unwrap().as_bytes())
}

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

// oauthlint-disable-next-line auth.rust.jwt.hardcoded-secret -- <reason>

References

https://docs.rs/jsonwebtoken/latest/jsonwebtoken/struct.EncodingKey.html#method.from_secret ↗https://cwe.mitre.org/data/definitions/798.html ↗