You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
genSaltSync accepts a non-integer cost and returns a salt that hashSync rejects #173
genSaltSync clamps the cost range but never checks it is an integer, so a fractional cost is formatted straight into the salt:
constbcrypt=require('bcryptjs');// 3.0.3constsalt=bcrypt.genSaltSync(10.5);// '$2b$10.5$OT90lVUoKI5OXCk88A2Z0.'bcrypt.hashSync('hunter2',salt);// Error: Missing salt rounds
genSalt returns a value its own hash cannot consume. Other bad inputs are handled at the call: 3 and -1 clamp to 04, 'abc' throws. index.js:93-99 checks the range only:
Number(process.env.BCRYPT_ROUNDS) on "10.5" is enough to hit it. Async genSalt behaves the same.
The same missing check on the parsing side is #167, still reproducible on 3.0.3:
bcrypt.hashSync('hunter2','$2a$xy$abcdefghijklmnopqrstuu');// '$2a$NaN$abcdefghijklmnopqrstuu...' 61 chars, 0.14 ms against 280 ms for cost 12
parseInt gives NaN, the rounds < 4 || rounds > 31 guard passes because NaN comparisons are false, and 1 << NaN is 1. That one was closed by the stale bot rather than triaged. Number.isInteger on each side covers both.
It rejects non-integer rounds (e.g. 10.5, Infinity) in genSaltSync / genSalt, and makes the range check in _crypt reject NaN when parsing a salt like $2a$xy$.... It also fixes hash(password, <number>) so a failing genSalt is reported properly instead of surfacing as Invalid string / salt: Not a string.
Valid integer costs behave as before. Tests are included, and npm run build, npm test and npm run lint pass locally. Let me know if you'd prefer a different approach, for example rounding instead of throwing, and I'm happy to adjust.
Activity
RajatX24 commentedon Nov 10, 2026
Hi! I've opened a PR for this: #177
It rejects non-integer
rounds(e.g.10.5,Infinity) ingenSaltSync/genSalt, and makes the range check in_cryptrejectNaNwhen parsing a salt like$2a$xy$.... It also fixeshash(password, <number>)so a failinggenSaltis reported properly instead of surfacing asInvalid string / salt: Not a string.Valid integer costs behave as before. Tests are included, and
npm run build,npm testandnpm run lintpass locally. Let me know if you'd prefer a different approach, for example rounding instead of throwing, and I'm happy to adjust.