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.flow.weak-bcrypt-rounds

A bcrypt cost factor below 10 was used.

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 low work factor makes the hash cheap to compute, which lets an attacker brute-force stolen password hashes far too quickly. OWASP recommends a bcrypt cost of at least 10, and ≥ 12 for new applications, tuned so a single hash takes roughly 250ms on your hardware.

Common LLM-generated mistake: bcrypt.hash(pw, 8) or bcrypt.genSalt(5) because the literal "looks fast enough". Raise the cost factor to 12 or higher.

VULNERABLE
vulnerable.ts
// `bcrypt` here is the bcryptjs package — the API surface is identical and
// LLMs frequently alias it to `bcrypt` on import.
import bcrypt from 'bcryptjs';

// ruleid: auth.flow.weak-bcrypt-rounds
export async function hashPassword(pw: string) {
  return bcrypt.hash(pw, 8);
}

// ruleid: auth.flow.weak-bcrypt-rounds
export async function makeSalt() {
  return bcrypt.genSalt(5);
}

// ruleid: auth.flow.weak-bcrypt-rounds
export function hashSyncPassword(pw: string) {
  return bcrypt.hashSync(pw, 9);
}

// ruleid: auth.flow.weak-bcrypt-rounds -- hash with 3-arg callback form
export function hashWithCallback(pw: string) {
  bcrypt.hash(pw, 4, (_err, _hash) => {});
}

// ruleid: auth.flow.weak-bcrypt-rounds -- genSaltSync low cost
export function makeSaltSync() {
  return bcrypt.genSaltSync(6);
}
SAFE
safe.ts
import bcrypt from 'bcrypt';

const saltRounds = 12;

// ok: auth.flow.weak-bcrypt-rounds
export async function hashPassword(pw: string) {
  return bcrypt.hash(pw, 12);
}

// ok: auth.flow.weak-bcrypt-rounds -- exactly at the recommended floor
export async function makeSalt() {
  return bcrypt.genSalt(10);
}

// ok: auth.flow.weak-bcrypt-rounds -- cost factor comes from a constant
export function hashWithConstant(pw: string) {
  return bcrypt.hashSync(pw, saltRounds);
}

// ok: auth.flow.weak-bcrypt-rounds -- cost factor from config variable
export function hashWithVar(pw: string, rounds: number) {
  return bcrypt.hash(pw, rounds);
}

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.weak-bcrypt-rounds -- <reason>

References

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