Profiles·Public

bcryptjs

semver>=2.0.0postconditions22functions9last verified2026-06-25coverage score75%

Postconditions: what we check

  • hash · hash-type-error
    error
    Whenpassword is not a string or Buffer, or salt is invalid type
    ThrowsError: Illegal arguments: [actual_type], [actual_type]
    Required handlingCaller MUST wrap bcrypt.hash() in try-catch block or use .catch() handler. Type errors occur when forgetting await on Promise or passing wrong types. Validate input types before calling hash() to provide better error messages.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • hash · hash-invalid-salt
    error
    Whensalt parameter is not a string, number, or valid salt format
    ThrowsError: Invalid salt version or Illegal arguments
    Required handlingCaller MUST handle errors from invalid salt parameter. Use genSalt() to generate valid salts, or pass numeric salt rounds (recommended: 12).
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • hash · hash-rounds-out-of-range
    error
    Whensalt rounds < 4 or > 31
    ThrowsError: Rounds out of range (4-31)
    Required handlingCaller MUST validate salt rounds are between 4 and 31. Production systems should use rounds >= 12 for adequate security.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3]
  • hash · hash-internal-failure
    error
    Wheninternal hashing operation fails
    ThrowsError
    Required handlingCaller MUST handle unexpected errors from hash() operation. While rare, internal failures can occur and should not crash the application.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4]
  • compare · compare-type-error
    error
    Whenpassword or hash parameter is not a string
    ThrowsError: Illegal arguments: [actual_type], [actual_type]
    Required handlingCaller MUST wrap bcrypt.compare() in try-catch or use .catch() handler. Type errors commonly occur when retrieving hash from database as Buffer instead of string, or when password input is undefined/null.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5]
  • compare · compare-invalid-hash
    error
    Whenhash parameter is not a valid bcrypt hash format
    ThrowsError: Invalid hash provided or hash is not a valid bcrypt hash
    Required handlingCaller MUST handle errors from malformed hash values. Database corruption, string truncation (VARCHAR < 60), or encoding issues can cause invalid hashes. This is the #1 production authentication bug.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • compare · compare-internal-failure
    error
    Wheninternal comparison operation fails
    ThrowsError
    Required handlingCaller MUST handle unexpected errors from compare() operation. Errors should not be silently swallowed as they may indicate security issues or data corruption.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4]
  • genSalt · gensalt-invalid-rounds
    error
    Whenrounds parameter < 4 or > 31
    ThrowsError: Rounds out of range (4-31)
    Required handlingCaller MUST wrap genSalt() in try-catch or use .catch() handler when rounds parameter could be invalid. Validate rounds before calling.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3]
  • genSalt · gensalt-type-error
    error
    Whenrounds parameter is not a number
    ThrowsError: Illegal arguments: [actual_type]
    Required handlingCaller MUST validate rounds is a number. Common error when reading from environment variables or config files without parsing to integer.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[7]
  • genSalt · gensalt-rng-failure
    error
    Whenrandom number generator fails (browser context without setRandomFallback)
    ThrowsError: Secure random number generator not available
    Required handlingCaller MUST handle RNG failures. In browser environments, call bcrypt.setRandomFallback() to provide a CSPRNG fallback.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8]
  • hashSync · hash-sync-type-error
    error
    Whenpassword is not a string or salt is not a string/number
    ThrowsError: Illegal arguments: [typeof password], [typeof salt]
    Required handlingCaller MUST wrap hashSync() in a try-catch block. Type errors throw synchronously. Most common cause: passing undefined/null password (unvalidated input) or an already-hashed password Buffer from a database query instead of a string. Unlike the async hash(), there is no .catch() available — only try-catch.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • hashSync · hash-sync-rounds-out-of-range
    error
    Whensalt is a number and rounds < 4 or > 31
    ThrowsError: Illegal number of rounds (4-31): [N]
    Required handlingCaller MUST wrap hashSync() in try-catch when rounds parameter comes from configuration or environment variables. Validate rounds is 4-31 before calling. Production minimum recommended: 12.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • hashSync · hash-sync-blocks-event-loop
    error
    WhenhashSync() is called in a Node.js HTTP request handler or any async context
    ThrowsDoes not throw — instead blocks event loop for 100ms-400ms+
    Required handlingCaller MUST NOT use hashSync() in Express/Fastify/Next.js API routes, background workers serving concurrent requests, or any code running in the main event loop. The operation blocks all other requests for its duration. Use async hash() instead. hashSync is ONLY appropriate in: CLI scripts, database seed files, one-time migration scripts, and test setup (beforeAll/beforeEach fixtures).
    costhighin proddegraded serviceusers seeservice unavailablevisibilityvisible
    Sources[10]
  • compareSync · compare-sync-type-error
    error
    Whenpassword or hash is not a string
    ThrowsError: Illegal arguments: [typeof password], [typeof hash]
    Required handlingCaller MUST wrap compareSync() in try-catch. Common cause: retrieving hash from database as Buffer instead of string, or passing undefined when the user record is not found. Unlike the async compare(), no .catch() is available.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • compareSync · compare-sync-silent-false-on-bad-hash
    error
    Whenhash parameter is a string but not exactly 60 characters (malformed bcrypt hash)
    Returnsfalse — NOT an error, not a throw. Silent authentication failure.
    Required handlingCallers who only check `if (isMatch)` without validating that the stored hash is well-formed will silently deny authentication for ALL users whose hashes were truncated, corrupted, or stored in a VARCHAR(40) column. Always validate that the hash column is VARCHAR(60) or CHAR(60) in the database schema and that the hash was not corrupted in transit. This is the #1 silent authentication bug with bcryptjs — the function returns false for wrong-password AND bad-hash, making it impossible to distinguish them without additional checks.
    costhighin prodsilent failureusers seeauthentication failurevisibilitysilent
    Sources[9][2]
  • compareSync · compare-sync-blocks-event-loop
    error
    WhencompareSync() is called in a Node.js HTTP request handler or async context
    ThrowsDoes not throw — instead blocks event loop for 100ms-400ms+
    Required handlingCaller MUST NOT use compareSync() in Express/Fastify/Next.js API routes or any code running in the main event loop. Use async compare() for all authentication endpoints. compareSync is ONLY appropriate in: CLI scripts, test setup, and one-off verification scripts.
    costhighin proddegraded serviceusers seeservice unavailablevisibilityvisible
    Sources[10]
  • genSaltSync · gensalt-sync-invalid-rounds
    error
    Whenrounds is not a number, or rounds < 4 or rounds > 31
    ThrowsError: Illegal arguments: [typeof rounds] (wrong type) or Error: Illegal number of rounds (4-31): [N] (out of range)
    Required handlingCaller MUST wrap genSaltSync() in try-catch when rounds comes from configuration or user input. Validate rounds is an integer between 4 and 31. Common error: reading BCRYPT_ROUNDS from environment variable as string without parseInt() — e.g., process.env.BCRYPT_ROUNDS returns '12' (string) not 12 (number).
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • genSaltSync · gensalt-sync-rng-failure
    error
    Whencalled in a browser environment without setting a random fallback via setRandomFallback()
    ThrowsError: Secure random number generator not available
    Required handlingIn browser environments, bcryptjs requires calling bcrypt.setRandomFallback() with a CSPRNG implementation before using any salt-generating functions. Node.js environments use crypto.randomBytes() automatically and are unaffected.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • getRounds · get-rounds-type-error
    error
    Whenhash parameter is not a string
    ThrowsError: Illegal arguments: [typeof hash]
    Required handlingCaller MUST wrap getRounds() in try-catch when the hash comes from a database column or external source where it could be null, undefined, a Buffer, or any non-string type. Common cause: the user record was not found (hash is undefined) and the calling code did not guard, so a synchronous throw bubbles up into a login or password-rotation handler that does not expect it. Validate that the hash is a string of length 60 before calling getRounds().
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • getSalt · get-salt-type-error
    error
    Whenhash parameter is not a string
    ThrowsError: Illegal arguments: [typeof hash]
    Required handlingCaller MUST wrap getSalt() in try-catch when the hash comes from a database row or external source where it may be null, undefined, or a non-string type (Buffer, Object). The function throws synchronously — there is no Promise and no .catch() path. Validate that the hash is a 60-character string before calling.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • getSalt · get-salt-illegal-length
    error
    Whenhash is a string but its length is not exactly 60 characters
    ThrowsError: Illegal hash length: [length] != 60
    Required handlingCaller MUST handle the length-validation throw. Common cause: the hash was stored in a VARCHAR column narrower than 60 (e.g. VARCHAR(40)), or it was trimmed/encoded on insert, or it was migrated from a different bcrypt variant (some libraries produce $2y$ hashes that may have different lengths). Unlike compareSync() which silently returns false for malformed hashes, getSalt() throws explicitly — so an uncaught throw will crash the handler. Validate hash.length === 60 before calling, or wrap the call.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • truncates · truncates-type-error
    error
    Whenpassword parameter is not a string
    ThrowsError: Illegal arguments: [typeof password]
    Required handlingCaller MUST wrap truncates() in try-catch or validate the input is a string first. Common cause: passing undefined when the user-submitted form field is missing, or passing a Buffer from a binary upload path. The function is synchronous — there is no Promise rejection or .catch() handler available.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation
Source code
Issues & pull requests

Research notes

Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.

Sources: bcryptjs

Official Documentation

Behavioral Evidence

Error Handling Pattern

The bcryptjs library uses an error-first callback pattern: Callback<T>: (err: Error | null, result?: T) => void, which is called with an error on failure or a value of type T upon success. Synchronous methods throw errors directly, while asynchronous methods pass errors to callbacks or reject promises.

Source: https://github.com/dcodeIO/bcrypt.js/blob/main/README.md

Input Constraints and Validation

Maximum Password Length

bcryptjs has a 72-byte maximum input length for passwords. Note that UTF-8 encoded characters can use up to 4 bytes each, so a 72-character string may exceed this limit depending on the characters used. Inputs exceeding this length are silently truncated, not rejected.

Source: https://github.com/dcodeIO/bcrypt.js README

Hash Format

All generated hashes are 60 characters in length and follow the format: $2a$[rounds]$[salt][hash]

Source: https://github.com/dcodeIO/bcrypt.js README

Function-Specific Error Conditions

hash() and hashSync()

Signatures:

  • hash(s: string, salt: string | number, callback?: (err: Error, hash: string) => void, progressCallback?: (percent: number) => void): Promise<string>
  • hashSync(s: string, salt: string | number): string

Error Conditions:

  1. Missing Salt Parameter

  2. Invalid Parameter Types

    • Error: Error: Illegal arguments: string, object
    • Occurs when passing non-string/non-number types (e.g., Buffer, Promise, undefined)
    • Common mistake: Not awaiting hash() before storing, causing Promise object to be passed to subsequent operations
    • Source: https://github.com/dcodeIO/bcrypt.js/issues/146
  3. Invalid Salt Format

    • Error: Error: Invalid salt version: 2 or Error: Invalid salt version: nu
    • Occurs when pre-generated salt string has incompatible version format
    • Can happen with hashes generated by different bcrypt implementations
    • Source: https://github.com/dcodeIO/bcrypt.js/issues/20
  4. Input Length Constraint

    • Behavior: Passwords exceeding 72 bytes are silently truncated (not an error)
    • Risk: "password123" and "password123[...very long suffix...]" may hash to the same value
    • Source: https://github.com/dcodeIO/bcrypt.js README

compare() and compareSync()

Signatures:

  • compare(s: string, hash: string, callback?: (err: Error, success: boolean) => void, progressCallback?: (percent: number) => void): Promise<boolean>
  • compareSync(s: string, hash: string): boolean

Error Conditions:

  1. Invalid Hash Parameter Type

    • Error: Error: Illegal arguments: string, undefined or Error: Illegal arguments: string, object
    • Occurs when hash is not a string (e.g., Buffer, undefined, null)
    • Common with database retrievals that return Buffer objects
    • Source: https://github.com/dcodeIO/bcrypt.js/issues/65
  2. Invalid Password Parameter Type

  3. Hash Version Mismatch

    • Error: Error: Invalid salt version
    • Occurs when hash uses unsupported or incompatible version identifier (e.g., $2$, $2x$)
    • bcryptjs primarily supports $2a$ format; $2b$ support added later
    • Source: https://github.com/dcodeIO/bcrypt.js/issues/81
  4. Empty Password Edge Case

  5. False Negatives from Database Storage

    • Symptom: compare() always returns false despite correct password
    • Common causes:
      • Hash stored as Buffer instead of string
      • Hash truncated in database (VARCHAR too short)
      • Hash modified during storage/retrieval (encoding issues)
    • Source: https://github.com/dcodeIO/bcrypt.js/issues/76

genSalt() and genSaltSync()

Signatures:

  • genSalt(rounds?: number, callback?: (err: Error, salt: string) => void): Promise<string>
  • genSaltSync(rounds?: number): string

Error Conditions:

  1. Invalid Rounds Type

  2. Rounds Below Minimum (< 4)

  3. Rounds Above Maximum (> 31)

    • Error: Error: Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue
    • Cryptic error message; actual issue is rounds exceeding bcrypt's log2(rounds) specification limit
    • bcrypt uses 5-bit field for rounds, max value is 31
    • Source: https://github.com/kelektiv/node.bcrypt.js/issues/437
  4. Missing Callback (Legacy)

Default Behavior:

  • If rounds is omitted, default is 10
  • Recommended range: 10-12 for most applications (as of 2026)

getRounds()

Signature:

  • getRounds(hash: string): number

Error Conditions:

  1. Non-String Parameter

  2. Malformed Hash

    • Behavior: May return incorrect value or throw
    • Implementation-dependent; no guaranteed error for invalid format
    • Recommended to validate hash format before calling

getSalt()

Signature:

  • getSalt(hash: string): string

Error Conditions:

IMPORTANT: getSalt() does NOT validate the hash parameter. It performs string manipulation without error checking.

  1. No Validation

Security Implication: Always validate hash format before calling getSalt() to avoid processing untrusted data.

Common Error Patterns and Debugging

"Illegal arguments" Error Family

The most common error in bcryptjs is Error: Illegal arguments: [type1], [type2], which indicates type mismatch between expected and actual parameters.

Common Causes:

  • Forgetting to await async operations
  • Passing Buffer objects from databases without .toString()
  • Passing environment variables (strings) as rounds parameter
  • Missing required parameters

Debugging Approach:

// Check actual types before calling bcryptjs
console.log(typeof password, typeof hash, typeof rounds);

Sources:

Hash Version Compatibility

bcryptjs primarily supports the $2a$ hash format. Support for $2b$ (which fixes a bug in the original specification) was added later. Mixing hash versions between generation and comparison can cause issues.

Recommendation: Use consistent bcryptjs versions across all systems that generate/verify hashes.

Source: https://github.com/dcodeIO/bcrypt.js/issues/81

Asynchronous Behavior

bcryptjs async functions split operations into small chunks. After each chunk completes, the next chunk is placed on the back of the JavaScript event queue, allowing other operations to execute. This prevents blocking the event loop during expensive hashing operations.

Progress Callbacks: Optional progressCallback parameter receives a number between 0.0 and 1.0 indicating completion percentage. Called at most once per 100ms (MAX_EXECUTION_TIME).

Source: https://github.com/dcodeIO/bcrypt.js README

Related Issues and Discussions

Key GitHub Issues

  1. Issue #146: Error: Illegal arguments: string, undefined

  2. Issue #20: ERROR: Invalid salt version: 2

  3. Issue #81: Add support "2b" hash

  4. Issue #58: genSalt (async) with no arguments throws callback error instead of returning promise

  5. Issue #65: compareSync throwing error

  6. Issue #898: Document the upper and lower bounds for the rounds parameter in genSaltSync

  7. Issue #437: Wrong error message being thrown when salt rounds value is too high

  8. Issue #76: bcrypt.compare always returns false

Best Practices Summary

Input Validation

  • Always validate that passwords and hashes are strings before calling bcryptjs
  • Check password length doesn't exceed 72 bytes (especially with UTF-8)
  • Validate rounds is a number between 4 and 31
  • Convert Buffer objects to strings: buffer.toString('utf8')

Error Handling

  • Wrap synchronous calls in try-catch blocks
  • Use error-first callback pattern or promise rejection handling for async calls
  • Check for null error parameter before proceeding with results
  • Log errors with context but avoid exposing sensitive details to users

Database Storage

  • Store hashes as VARCHAR(60) or TEXT
  • Always store as strings, not Buffers
  • Verify encoding is consistent (UTF-8 recommended)
  • Test hash retrieval in development to catch storage issues early

Async/Await Pattern

try {
  const hash = await bcrypt.hash(password, rounds);
  // Use hash immediately after awaiting
} catch (error) {
  // Handle error
}

DO NOT:

const hash = bcrypt.hash(password, rounds); // Missing await
// hash is now a Promise, not a string!

Security Considerations

CVE Status

No known CVEs for bcryptjs. As of 2026-02-26, the bcryptjs package has no security vulnerabilities in the NVD (National Vulnerability Database), Snyk, or GitHub Security Advisory databases.

Important Distinction: CVE-2020-7689 affects the bcrypt package (kelektiv/node.bcrypt.js with native C++ bindings), NOT the bcryptjs package (dcodeIO/bcrypt.js pure JavaScript implementation).

Sources:

CVE-2020-7689 (bcrypt Native Package)

For context, the native bcrypt package (not bcryptjs) was affected by CVE-2020-7689, a data truncation vulnerability:

  • Severity: 7.5 HIGH (NIST), 5.9 MEDIUM (Snyk)
  • Affected: bcrypt versions <5.0.0
  • Issue: Data exceeding 255 bytes was incorrectly truncated
  • Fixed: bcrypt v5.0.0
  • bcryptjs Status: NOT AFFECTED (pure JavaScript implementation)

Source: https://portswigger.net/daily-swig/bcrypt-hashing-library-bug-leaves-node-js-applications-open-to-brute-force-attacks

Recommended Versions

  • Minimum: 2.4.3
  • Recommended: 3.0.3 (latest as of 2026-02-26)
  • Reason: Active maintenance, TypeScript support, zero known vulnerabilities

Source: https://security.snyk.io/package/npm/bcryptjs

Security Best Practices

1. Use Appropriate Rounds Value (2026)

For modern hardware, use rounds between 10-14:

  • 10 rounds: Fast, suitable for high-traffic applications
  • 12 rounds: Balanced security/performance (recommended)
  • 14 rounds: Higher security, slower hashing

Valid Range: 4-31 (specification limit)

Source: https://auth0.com/blog/hashing-in-action-understanding-bcrypt/

2. Validate Password Length

Passwords exceeding 72 bytes are silently truncated. This is a bcrypt algorithm limitation, not a bug.

Risk: Long passwords may hash to the same value:

// These may produce the same hash if both exceed 72 bytes:
"password" + "A".repeat(100)
"password" + "B".repeat(100)

Mitigation:

  • Validate password length at application layer
  • Consider pre-hashing with SHA-256 for very long passwords
  • Document the 72-byte limit to users

Source: https://github.com/dcodeIO/bcrypt.js README

3. Timing Attack Protection

bcryptjs implements constant-time comparison in the compare() function to prevent timing attacks. The function compares strings character-by-character without early bailout.

Important: Never use standard JavaScript string comparison (===) for password verification. Always use bcrypt.compare() or bcrypt.compareSync().

Sources:

4. Database Storage Security

Column Size: Use VARCHAR(60) or larger to prevent hash truncation.

Type Safety:

  • Store hashes as strings, not Buffers
  • Convert Buffer objects before comparison: buffer.toString('utf8')
  • Use UTF-8 encoding consistently

Validation:

  • Test hash retrieval in development
  • Verify no truncation occurs
  • Check encoding matches storage format

Source: https://github.com/dcodeIO/bcrypt.js/issues/76

5. Hash Version Compatibility

bcrypt has multiple version identifiers:

  • $2$ - Original (deprecated)
  • $2a$ - Most common (has wraparound bug for passwords >254 chars)
  • $2b$ - Fixed wraparound bug (recommended)
  • $2x$, $2y$ - Variant implementations (deprecated)

bcryptjs Support: Supports $2a$ and $2b$ formats

Recommendation: Use consistent library versions across systems. For passwords under 256 characters, $2a$ and $2b$ are functionally identical.

Sources:

6. Browser Environment Security

WARNING: In browser environments without crypto.getRandomValues(), bcryptjs falls back to Math.random(), which is NOT cryptographically secure.

Mitigation:

// Set a cryptographically secure PRNG for browsers
bcrypt.setRandomFallback((len) => {
  const buf = new Uint8Array(len);
  window.crypto.getRandomValues(buf);
  return Array.from(buf);
});

Node.js: Automatically uses crypto.randomBytes() (secure)

Source: https://github.com/dcodeIO/bcrypt.js/issues/110

7. Environment Variable Handling

Environment variables are always strings. Convert to numbers:

// ❌ WRONG
const rounds = process.env.SALT_ROUNDS; // "10" (string)
await bcrypt.genSalt(rounds); // Error: rounds must be a number

// ✅ CORRECT
const rounds = parseInt(process.env.SALT_ROUNDS, 10); // 10 (number)
await bcrypt.genSalt(rounds);

Source: https://github.com/kelektiv/node.bcrypt.js/issues/903

8. getSalt() Input Validation

WARNING: getSalt() does NOT validate input. It returns substrings without error checking.

Risk: May return garbage data for invalid hashes.

Mitigation: Use getRounds() instead, which validates input. Or validate hash format before calling getSalt().

Source: https://snyk.io/advisor/npm-package/bcryptjs/functions/bcryptjs.getSalt

Security Comparison: bcryptjs vs Native bcrypt

Aspectbcrypt (Native)bcryptjs (Pure JS)
CVE-2020-7689Affected (<5.0.0)Not affected
Dependenciesnode-gyp, native bindingsZero dependencies
Performance~30% fasterSlower (security feature)
PlatformNode.js only, requires compilationNode.js + browsers
VulnerabilitiesPlatform-specific risksNo native code vulnerabilities
Security PostureRequires regular updatesStable, well-vetted

Recommendation: bcryptjs is particularly well-suited for:

  • Cross-platform applications (Node.js + browser)
  • Environments where native compilation is problematic
  • Projects prioritizing zero-dependency security

Source: https://codeforgeek.com/bcrypt-vs-bcryptjs/

Alternative Consideration: Argon2id (2026)

For new projects in 2026, consider Argon2id, which provides:

  • Memory-hardness (resistant to GPU/ASIC attacks)
  • Configurable memory and parallelism parameters
  • Winner of the Password Hashing Competition (2015)

bcrypt Status: Remains secure and widely vetted. No urgent need to migrate existing systems.

Migration Strategy: Opportunistic rehashing (rehash on successful login)

Source: https://thelinuxcode.com/npm-bcrypt-in-2026-password-hashing-that-fails-closed-and-how-to-ship-it-safely/

Security Audit Summary

Package: bcryptjs v3.0.3 Audit Date: 2026-02-26 Status: ✅ SECURE

Findings:

  • ✅ No known CVEs
  • ✅ Active maintenance (last update <3 months)
  • ✅ Zero dependencies (minimal attack surface)
  • ✅ Constant-time comparison (timing attack protection)
  • ✅ Platform-independent (no native code vulnerabilities)

Caveats:

  • ⚠️ Silent 72-byte truncation (application-layer validation required)
  • ⚠️ getSalt() lacks input validation
  • ⚠️ Browser environments need secure random fallback
  • ⚠️ Slower than native bcrypt (~30% performance penalty)

Recommendation: Safe for production use with proper error handling and input validation.

Contract Justification

This contract requires error handling because:

  1. Type validation failures are common and throw/reject errors
  2. Invalid hash formats cause runtime errors
  3. Out-of-range parameters (rounds, salt) trigger errors
  4. Async operations can fail and reject promises
  5. Database type mismatches (Buffer vs string) are frequent in production

The library is designed to fail fast on invalid inputs rather than silently producing incorrect results, making error handling essential for reliable applications.

Need a different package?
Request a profile