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

OAuth authorization request is built with 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.

Generate state fresh per request from a CSPRNG (e.g. crypto/rand -> base64.URLEncoding.EncodeToString(b)), persist it in the session/cookie, and verify it when the provider redirects back. With golang.org/x/oauth2, pass that random value as the first argument to Config.AuthCodeURL(state, ...).

VULNERABLE
vulnerable.go
package main

import (
	"golang.org/x/oauth2"
)

// Hardcoded state passed to AuthCodeURL — constant on every request.
func authorizeStatic(conf *oauth2.Config) string {
	// ruleid: auth.go.oauth.static-state
	return conf.AuthCodeURL("xyz123")
}

// Hardcoded state alongside extra AuthCodeOption arguments.
func authorizeStaticWithOpts(conf *oauth2.Config) string {
	// ruleid: auth.go.oauth.static-state
	return conf.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
}

func main() {}
SAFE
safe.go
package main

import (
	"crypto/rand"
	"encoding/base64"

	"golang.org/x/oauth2"
)

// randomState returns a fresh CSPRNG-backed state value.
func randomState() string {
	b := make([]byte, 32)
	_, _ = rand.Read(b)
	return base64.URLEncoding.EncodeToString(b)
}

// Safe: a per-request random state generated from crypto/rand.
func authorizeRandom(conf *oauth2.Config) string {
	state := randomState()
	// ok: auth.go.oauth.static-state
	return conf.AuthCodeURL(state, oauth2.AccessTypeOffline)
}

// Safe trap: the empty-string form is a missing state (covered elsewhere),
// not a hardcoded literal, and must not be flagged by this rule.
func authorizeEmpty(conf *oauth2.Config) string {
	// ok: auth.go.oauth.static-state
	return conf.AuthCodeURL("")
}

func main() {}

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

References

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