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 →
MEDIUM AI PREVALENCE: MEDIUM auth.java.oauth.static-state

OAuth authorization request sends a hardcoded, constant state value.

Why AI tools produce this: AI coding tools produce this regularly, typically when prompted for a shortcut or a quick fix.

Why this matters

A static state provides ZERO CSRF protection: the whole point is an unguessable, per-request value that you store and then compare on the callback. A literal that ships in your source is known to everyone and identical on every request, so an attacker can forge a matching callback (CWE-330).

Generate state fresh per request from a CSPRNG (new SecureRandom() / Base64.getUrlEncoder().encodeToString(randomBytes)), persist it in the session, and verify it when the provider redirects back.

VULNERABLE
vulnerable.java
class AuthorizeRequest {

    // Inline authorize URL literal carrying both response_type and a constant
    // state value.
    String build() {
        // ruleid: auth.java.oauth.static-state
        return "https://idp.example.com/authorize?response_type=code&client_id=web&state=xyz123&scope=openid";
    }

    // Constant state placed before response_type in the same literal.
    String fixed() {
        // ruleid: auth.java.oauth.static-state
        return "https://idp.example.com/oauth/authorize?state=abc&client_id=web&response_type=code";
    }
}
SAFE
safe.java
import java.security.SecureRandom;
import java.util.Base64;

class AuthorizeRequest {

    // Per-request state generated from a CSPRNG and appended by concatenation —
    // the literal ends right after `state=`, so no constant value is present.
    String build(String clientId) {
        // ok: auth.java.oauth.static-state
        byte[] bytes = new byte[32];
        new SecureRandom().nextBytes(bytes);
        String state = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
        return "https://idp.example.com/authorize?response_type=code&client_id=" + clientId
            + "&state=" + state;
    }

    // True-negative trap: a URL with a constant `state=` but NO response_type,
    // so it is not an authorize request and must not be flagged.
    String unrelated() {
        // ok: auth.java.oauth.static-state
        return "https://app.example.com/page?state=open&tab=1";
    }
}

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.java.oauth.static-state -- <reason>

References

https://datatracker.ietf.org/doc/html/rfc6749#section-10.12 ↗https://cwe.mitre.org/data/definitions/330.html ↗