RocketChat / RocketChat/Rocket.Chat

fix: Base64.decode() silently produces corrupted output for invalid characters instead of throwing

Open Beginner friendly
#42,157 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: bug
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 returns Uint8Array([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 throw Error('invalid base64 string')
  • Base64.decode('A!AA') should throw Error('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

Acceptance Criteria

  • Base64.decode('!!!!') throws Error('invalid base64 string')
  • Base64.decode('A!AA') throws Error('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:unit passes

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.