gchq/CyberChef · error · OperationError
${err.toString()}
Error message
${err.toString()} What it means
Generic catch-all thrown by BcryptCompare.run when bcrypt.compare rejects its arguments rather than resolving to false. bcrypt.compare expects a valid bcrypt hash string as its second argument (the hash from args[0]); if that hash is malformed (wrong version prefix, bad cost, invalid base64 salt, truncated), bcrypt throws and the original Error.toString() is forwarded. A genuine non-match resolves to false and yields 'No match', not this error.
Source
Thrown at src/core/operations/BcryptCompare.mjs:55
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const hash = args[0];
let match;
try {
match = await bcrypt.compare(input, hash, undefined, p => {
// Progress callback
if (isWorkerEnvironment())
self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
});
} catch (err) {
throw new OperationError(err.toString());
}
return match ? "Match: " + input : "No match";
}
}
export default BcryptCompare;
View on GitHub (pinned to 4290ea7539)
Solutions
- Ensure the hash argument is a full, valid bcrypt hash (e.g. $2b$12$... 60 characters).
- Trim whitespace/newlines from the stored hash before comparing.
- If you have a non-bcrypt hash, use the matching verify operation instead.
- Distinguish this error (malformed hash) from a normal 'No match' result (valid hash, wrong password).
Example fix
// before - truncated/malformed hash
chef.bcryptCompare("pw", "$2b$12$abc");
// after - full 60-char bcrypt hash
chef.bcryptCompare("pw", "$2b$12$abcdefghijklmnopqrstuuVXQ1Nh2yTLB07h2yTLB07h2yTLB07h"); Defensive patterns
Strategy: validation
Validate before calling
const BCRYPT_HASH_RE = /^\$2[aby]\$\d{2}\$[./A-Za-z0-9]{53}$/;
function assertBcryptHash(hash) {
const h = String(hash).trim();
if (!BCRYPT_HASH_RE.test(h)) {
throw new Error("Not a valid bcrypt hash (expected $2a/$2b/$2y$<cost>$<53 base64 chars>)");
}
return h;
}
assertBcryptHash(hash); Type guard
function isBcryptHash(s) {
return /^\$2[aby]\$\d{2}\$[./A-Za-z0-9]{53}$/.test(String(s).trim());
} Try / catch
try {
await chef.bcryptCompare(input, hash);
} catch (e) {
if (/illegal|invalid|hash|salt/i.test(e.message)) {
throw new Error(`Stored hash is not a valid bcrypt hash: ${e.message}`);
}
throw e;
} Prevention
- Store full 60-character bcrypt hashes only.
- Trim whitespace/newlines from stored hashes before comparing.
- Distinguish a thrown error (malformed hash) from a 'No match' result (valid hash, wrong input).
When it happens
Trigger: Passing a hash that is not a $2a$/$2b$/$2y$ bcrypt string, a hash with a missing or invalid cost factor, a corrupted base64 salt section, or a hash truncated below the 60-character minimum.
Common situations: Comparing against an MD5/SHA hash by mistake; hash copied incompletely (bcrypt hashes are 60 chars); version prefix stripped during copy; whitespace/newline accidentally included in the stored hash.
Related errors
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/239209f074ab0179.
Report an issue: GitHub.