{"record":{"id":"3a0eeb2bbb12d206","repo":"gchq/CyberChef","slug":"invalid-padding-too-many-bits-remaining","errorCode":null,"errorMessage":"Invalid padding: too many bits remaining","messagePattern":"Invalid padding: too many bits remaining","errorType":"validation","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/Bech32.mjs","lineNumber":149,"sourceCode":"export function fromWords(words) {\n    let value = 0;\n    let bits = 0;\n    const result = [];\n\n    for (let i = 0; i < words.length; i++) {\n        value = (value << 5) | words[i];\n        bits += 5;\n\n        while (bits >= 8) {\n            bits -= 8;\n            result.push((value >> bits) & 255);\n        }\n    }\n\n    // Check for invalid padding per BIP-0173\n    // Condition 1: Cannot have 5+ bits remaining (would indicate incomplete byte)\n    if (bits >= 5) {\n        throw new OperationError(\"Invalid padding: too many bits remaining\");\n    }\n    // Condition 2: Remaining padding bits must all be zero\n    if (bits > 0) {\n        const paddingValue = (value << (8 - bits)) & 255;\n        if (paddingValue !== 0) {\n            throw new OperationError(\"Invalid padding: non-zero bits in padding\");\n        }\n    }\n\n    return result;\n}\n\n/**\n * Encode data to Bech32/Bech32m string\n *\n * @param {string} hrp - Human-readable part\n * @param {number[]|Uint8Array} data - Data bytes to encode\n * @param {string} encoding - \"Bech32\" or \"Bech32m\"","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/Bech32.mjs#L131-L167","documentation":"Thrown by fromWords() in src/core/lib/Bech32.mjs:149 when converting 5-bit Bech32 words back to 8-bit bytes leaves 5 or more uncommitted bits. Per BIP-0173, the data part of a valid Bech32 string must not leave a residual of 5+ bits after the final byte — such a residual can only arise from a malformed or truncated word sequence, because each word contributes 5 bits and a full byte consumes 8.","triggerScenarios":"fromWords(words) where words.length produces bits in {5,6,7} at the end with no further word to flush — e.g. a single word [0] gives bits=5 after the loop, throwing. In practice reached via decode() of a string whose data part (minus checksum) has a length that leaves >=5 residual bits, or by calling fromWords directly with a short array.","commonSituations":"Decoding a truncated Bech32 string that passed checksum by accident (or with checksum disabled upstream); hand-crafted test vectors with wrong word counts; feeding the full data part including the 6-word checksum into fromWords instead of slicing it off first.","solutions":["Ensure you pass only the data words (checksum stripped) to fromWords — the library does this internally in decode().","Validate the source string's checksum before decoding; a bad checksum often signals truncation.","If calling fromWords directly, confirm words.length * 5 leaves a residual < 5 bits (i.e. (words.length*5) % 8 must not produce 5-7 leftover).","Re-acquire the Bech32 string from its origin; truncation is the usual cause."],"exampleFix":"// before - passing a too-short / malformed word list\nconst bytes = fromWords([0]);\n\n// after - decode through the public API which strips checksum and validates\nconst { data } = decode(bech32String);","handlingStrategy":"validation","validationCode":"function wordCountIsValid(words) {\n  // After consuming words, residual bits = (words.length * 5) % 8; must be < 5\n  return ((words.length * 5) % 8) < 5;\n}","typeGuard":"function isPlausibleBech32WordArray(words) {\n  return Array.isArray(words) && words.every(w => w >= 0 && w < 32) && ((words.length * 5) % 8) < 5;\n}","tryCatchPattern":"try {\n  const bytes = fromWords(words);\n} catch (e) {\n  if (e instanceof OperationError && /too many bits remaining/.test(e.message)) {\n    // word list is truncated or malformed; re-acquire source\n  }\n}","preventionTips":["Decode through the public decode() API rather than calling fromWords directly.","Always slice off the 6 checksum words before converting data words to bytes.","Validate the checksum first; truncation usually fails checksum too."],"tags":["bech32","decoding","bip-0173","padding","input-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}