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 →
LOW AI PREVALENCE: HIGH auth.flow.no-rate-limit

A /login, /signin, /auth, or /reset-password POST handler is registered without any rate-limit middleware in scope.

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

Without a rate limit, credential-stuffing and brute-force attacks are essentially free for the attacker.

Add express-rate-limit, @fastify/rate-limit, or a gateway-level WAF rule. Per-IP + per-account is the typical pairing.

VULNERABLE
vulnerable.ts
type Handler = (...args: unknown[]) => unknown;
declare const app: { post: (path: string, handler: Handler) => void };
declare const router: { post: (path: string, handler: Handler) => void };
declare const fastify: { post: (path: string, handler: Handler) => void };

function loginHandler(_req: unknown, _res: unknown) {
  /* ... */
}

// ruleid: auth.flow.no-rate-limit
app.post('/login', loginHandler);

// ruleid: auth.flow.no-rate-limit
app.post('/signin', loginHandler);

// ruleid: auth.flow.no-rate-limit
app.post('/reset-password', loginHandler);

// ruleid: auth.flow.no-rate-limit -- router, not app
router.post('/auth/login', loginHandler);

// ruleid: auth.flow.no-rate-limit -- fastify
fastify.post('/login', loginHandler);

// ruleid: auth.flow.no-rate-limit -- path prefix
app.post('/api/v1/login', loginHandler);
SAFE
safe.ts
type Mw = (req: unknown, res: unknown, next: () => void) => void;
type Handler = (req: unknown, res: unknown) => void;
declare const app: {
  post: (path: string, ...rest: (Mw | Handler)[]) => void;
};

const rateLimit =
  (_opts: { max: number }): Mw =>
  (_req, _res, next) => {
    next();
  };

const loginLimiter = rateLimit({ max: 5 });
function loginHandler(_req: unknown, _res: unknown) {
  /* ... */
}

// ok: auth.flow.no-rate-limit -- rate-limit middleware present (3-arg form)
app.post('/login', loginLimiter, loginHandler);

// ok: auth.flow.no-rate-limit -- not a login endpoint
app.post('/products', loginHandler);

// ok: auth.flow.no-rate-limit -- /authorize is the OAuth authorize endpoint, not a credential login
app.post('/oauth/authorize', loginHandler);

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.flow.no-rate-limit -- <reason>

References

https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html ↗