RocketChat / RocketChat/Rocket.Chat
fix: Base64.decode() silently produces corrupted output for invalid characters instead of throwing
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 46.1k
- Forks
- 13.9k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 130
Description
Base64.decode() Silent Data Corruption Bug
Description
Base64.decode() in @rocket.chat/base64 has a bug where invalid characters are silently skipped instead of throwing an error, producing corrupted output without any signal to the caller.
The root cause is in the getVal() function:
const getVal = (ch: string) => (ch === '=' ? -1 : BASE_64_VALS[ch]);
For characters not in the Base64 alphabet (e.g., !, @, #, spaces, newlines), BASE_64_VALS[ch] returns undefined.
The validation checks on lines 101 and 108 use if (v < 0) to detect invalid characters. However, in JavaScript, undefined < 0 evaluates to false, so the check never fires for invalid characters. The invalid values silently fall through, producing corrupted binary output.
Steps to Reproduce
import { Base64 } from '@rocket.chat/base64';
// This should throw an error, but instead silently returns corrupted data
const result = Base64.decode('!!!!');
console.log(result); // Uint8Array([0, 0, 0]) - silently corrupted output
// This should also throw, but silently skips the invalid character
const result2 = Base64.decode('A!AA');
console.log(result2); // Produces output without any error
Current Behavior
Base64.decode('!!!!')silently succeeds and returnsUint8Array([0, 0, 0])Base64.decode('A!AA')silently produces output with no error- No exception is thrown for any invalid Base64 character
Expected Behavior
Base64.decode('!!!!')should throwError('invalid base64 string')Base64.decode('A!AA')should throwError('invalid base64 string')- Any character outside
A-Z,a-z,0-9,+,/, and=should be rejected
Root Cause
In base64.ts:8:
const getVal = (ch: string) => (ch === '=' ? -1 : BASE_64_VALS[ch]);
BASE_64_VALS is an object mapping valid Base64 characters to their numeric values (0-63). For any character NOT in this map, the lookup returns undefined.
The validation on lines 101-103:
if (v < 0) {
throw new Error('invalid base64 string');
}
This check does not catch undefined because undefined < 0 is false in JavaScript.
Proposed Fix
Change getVal to return a sentinel value for unknown characters:
const getVal = (ch: string) => (ch === '=' ? -1 : (BASE_64_VALS[ch] ?? -2));
This way, invalid characters return -2, which correctly triggers the existing if (v < 0) check and throws the appropriate error.
Test Coverage Gaps
The existing test file base64.spec.ts lacks tests for:
- Invalid Base64 input strings (the bug described above)
- The string input branch of
encode()(line 17-29) - The non-ASCII character error path in
encode()(line 23) Base64.newBinary()(line 14)
Relevant Files
- packages/base64/src/base64.ts — Source with the bug
- packages/base64/src/base64.spec.ts — Existing tests (missing error case coverage)
Acceptance Criteria
-
Base64.decode('!!!!')throwsError('invalid base64 string') -
Base64.decode('A!AA')throwsError('invalid base64 string') -
Base64.decode()correctly rejects whitespace, special characters, and non-ASCII input - All existing passing tests remain green
- New tests added for invalid input, string encode path, and non-ASCII error path
-
yarn workspace @rocket.chat/base64 test:unitpasses
Hi! I found this silent data corruption bug while reading through the @rocket.chat/base64 package. The fix is a one-line change to getVal(), and I'd also like to add the missing error- case tests. If this looks good, could you please assign it to me?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/base64/src/base64.ts, especially getVal() and the existing decode validation, then review packages/base64/src/base64.spec.ts. Add regression coverage for invalid characters, whitespace, and non-ASCII input while preserving existing behavior. Run yarn workspace @rocket.chat/base64 test:unit; done means the specified inputs throw the expected error and all tests pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 90/100