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.