Engineering note / Error handling

Handling invalid bcrypt salt errors as operation errors

Confining dependency validation failures to CyberChef’s expected user-facing error path without changing successful bcrypt comparisons.

Project
CyberChef
Contribution
PR #2615
Related issue
Issue #2535
Role
PR author
Outcome
Merged 3 July 2026

A malformed hash escaped the operation’s expected error boundary.

CyberChef’s Bcrypt compare operation delegates hash validation and comparison to bcryptjs. For malformed hashes, including an invalid salt version, that dependency throws a JavaScript error. Before PR #2615, the error propagated through CyberChef’s unexpected-operation path rather than its normal user-facing operation error path.

Zain authored the merged fix for issue #2535. The change does not relax bcrypt validation; it changes how a validation failure is represented within CyberChef.

The dependency call had no operation-level boundary.

BcryptCompare.run() awaited bcrypt.compare() directly. Valid comparisons produced the usual match result, but any validation exception retained its generic JavaScript error type. CyberChef distinguishes expected input/operation failures with OperationError, so the missing conversion changed presentation and diagnostics for malformed input.

Wrap only the comparison call.

The patch imports OperationError and places a try/catch around bcrypt.compare(). A dependency error is rethrown as OperationError with the original error text. The progress callback and the successful “Match” or “No match” output remain unchanged.

try {
    match = await bcrypt.compare(input, hash, ...);
} catch (error) {
    throw new OperationError(error.toString());
}

Protect the malformed salt-version case.

The regression recipe passes a hash with an invalid $ab$ prefix and expects the operation output Error: Invalid salt version: $a. The PR record documents all 2,057 operation tests passing, lint passing, and a separate Node API run whose unrelated cleanup error was explicitly identified rather than counted as a successful suite.

Dependency errors should cross application boundaries deliberately.

  • Keep strict dependency validation, but translate expected input failures into the host application’s error type.
  • Place the boundary around the smallest call that can fail so unrelated logic retains its normal behavior.
  • Regression tests should assert the user-visible representation, not only that an exception occurred.

Authoritative upstream record.