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 →
OPEN SOURCE · MIT · BUILT ON SEMGREP

AI ships the auth bug.
OAuthLint catches it before the PR.

A static-analysis linter for the OAuth, OIDC, JWT, MCP, session, and CORS anti-patterns that AI coding tools generate by default, including GitHub Copilot, Cursor, and Claude Code. 270+ hand-curated rules spanning eleven languages, from JavaScript and Python to Go, C#, and Kotlin, plus mobile auth (Swift/iOS, Android) and a dedicated pack for MCP server auth. Tuned for zero false positives on the clean auth libraries developers actually depend on.

$

scanning 47 files…

CRITICAL jwt-no-verification src/auth/session.ts:42

HIGH token-in-localstorage src/login.tsx:18

MEDIUM cookie-no-secure src/server.ts:37

3 issues · 1 critical · 1 high · scanned in 1.7s

0
false positives · clean libs
100%
findings hand-verified
CWE·OWASP
every rule mapped
MIT
free & open, forever
WHY THIS EXISTS · INDEPENDENT RESEARCH
74
confirmed CVEs traced to AI-generated code, and authentication bypass is among the most common.
Georgia Tech · "Bad Vibes" ↗
~2×
the baseline rate at which AI-assisted commits leak secrets into public repositories.
GitGuardian · Secrets Sprawl 2026 ↗
+153%
design-level flaws in AI-generated code, including auth bypass and broken session handling.
Apiiro · Fortune 50 study ↗

// AI writes auth from a decade of insecure examples. These are the bugs it ships, and the ones OAuthLint catches. Read our own measurement →

THE PROBLEM

The same findings, in every AI-generated PR.

LLMs learned auth from a decade of insecure answers. The code compiles, passes your tests, and ships a token-forgery bug. Here is exactly how OAuthLint reports each one.

CRITICAL jwt-no-verification auth/session.ts:42
const claims = jwt.decode(token)

JWT decoded but never verified. The signature is never checked, so claims can be forged.

jwt.verify(token, key, { algorithms: ['RS256'] })
HIGH token-in-localstorage login.tsx:28
localStorage.setItem('access_token', t)

Access token in localStorage is readable by any XSS. It cannot be protected from script.

Set an HttpOnly, Secure, SameSite=Lax cookie server-side
HIGH oauth-state-missing routes/callback.ts:9
res.redirect(authorizeUrl) // no state

Authorization request without state (and PKCE) is open to CSRF and code interception.

Add a state param + PKCE code_challenge to the authorize URL
HIGH cors-reflected-origin server/cors.ts:6
ACAO = req.headers.origin + creds

Reflecting the request Origin with credentials defeats the same-origin policy entirely.

Match Origin against an explicit allowlist; never reflect it
HOW IT WORKS

Scan, triage, fix. Right where you work.

01 / SCAN

One command, or zero clicks

Run it locally, on every PR via the GitHub Action, inline as you type in VS Code, or right inside your AI coding tool with the MCP server, so the model checks its own auth code before it reaches you.

$ npx oauthlint scan
02 / TRIAGE

Sorted by severity, not noise

Findings rank critical → info, each mapped to CWE/OWASP. Near-zero false positives means every red line is worth your time.

● 1 CRIT● 2 HIGH● 3 MED
03 / FIX

A fix for every finding

Many rules rewrite the code for you with --fix (preview with --fix-dry-run). The rest ship a vulnerable and a corrected snippet, so the fix is copy-paste obvious, not a CWE number to look up.

$ oauthlint scan --fix
PROOF

Signal you can trust, measured in the open.

A linter is only as useful as its precision. We hold OAuthLint to a hard silence bar on clean libraries, then measure how often these anti-patterns actually show up in AI-generated code.

0
FALSE POSITIVES ACROSS
CLEAN AUTH LIBRARIES
jose✓ 0 findings
passport.js✓ 0 findings
authlib✓ 0 findings
coreos/go-oidc✓ 0 findings

Fire on a correct, idiomatic auth library and that's a bug in the rule. It doesn't ship.

Patterns common in AI-generated code

v0.4 aggregate across public AI-generated repositories
132
REPOSITORIES SCANNED
27%
HAD AT LEAST ONE FINDING
18%
HAD A HIGH+ FINDING
57%
OF FINDINGS ON RULES COMMON IN AI CODE
MOST COMMON PATTERN
FINDINGS
% OF REPOS
Non-constant-time secret comparisonCWE-208
75
13%
Auth tokens in browser storageCWE-922
60
8%
Session identifier in the URLCWE-598
27
8%
Hard-coded provider / API keysCWE-798
27
5%
No rate limiting on auth endpointsCWE-307
23
4%
Secrets written to logsCWE-532
8
2%
No AI tool named. Aggregate counts only. Read the full measured report →

// measured aggregate figures from our own scan. Full methodology & dataset on the research page.

COVERAGE

Every language you ship auth in. Every auth surface.

The rule pack grows with the ecosystem. Today it covers these languages and mobile auth (Swift/iOS, Android), with more landing every release.

JS / TypeScript Python Go Java Rust C# / .NET PHP Ruby Kotlin Swift / iOS Android + more coming
OAuth 2.0 OIDC JWT Session Cookies CORS Secrets
INTEGRATIONS

Lives where your code already does.

GitHub Action

PR annotations on the exact line, plus SARIF upload to code scanning.

auth/session.ts
! jwt-no-verification
critical · CWE-347

Editors & IDEs

Inline diagnostics as you type, in VS Code, Cursor, Windsurf, and every JetBrains IDE. Squiggle on the call, hover for the fix.

41  const c = jwt.decode(t)
decoded but never verified

CLI & CI

Exit non-zero on a threshold you set. JSON, SARIF or pretty output.

$ oauthlint scan --fail-on high
✗ 1 critical, 2 high
exit 1: build blocked
HONEST ANSWER

Why a dedicated auth linter, not a generic one?

OAuthLint runs on Semgrep's engine, and we love it. But a generic engine with a thousand community rules is a different thing from a curated, auth-only ruleset with dataflow, taint tracking, and a precision guarantee. That gap is the work we do so you don't have to.

CURATION

Rules chosen and tuned for AI-generated auth code, not thousands of generic patterns you have to triage.

PRECISION

A hard 0-false-positive bar on real auth libraries. Every benchmark finding hand-verified before release.

FIXES, NOT FLAGS

Vulnerable + safe example for every rule, mapped to CWE/OWASP. The remediation is in the finding.

Scan your codebase in 30 seconds.

No signup, no config, no account. Point it at your source and read the findings.

$ npx oauthlint scan ./src
Star on GitHub ↗