Skip to content

fix: reject interior padding in rfc4648 decode - #344

Open
maximilliangrand wants to merge 1 commit into
multiformats:masterfrom
maximilliangrand:fix/reject-interior-padding
Open

fix: reject interior padding in rfc4648 decode#344
maximilliangrand wants to merge 1 commit into
multiformats:masterfrom
maximilliangrand:fix/reject-interior-padding

Conversation

@maximilliangrand

Copy link
Copy Markdown

The rfc4648 padded codecs (base64pad, base64urlpad, base32pad, base32hexpad and the upper variants) accept a = in the middle of a string and decode it to bogus bytes instead of rejecting it.

Repro on 14.0.5:

import { base64pad } from 'multiformats/bases/base64'
base64pad.decode('MQQ=Q') // => Uint8Array(3) [0x41, 0x10, 0x10]
base64pad.decode('MQ=Q=') // => Uint8Array(2) [0x44, 0x04]

Per RFC 4648 §3.2 the = padding may only appear as a trailing run, so both inputs are invalid. Python agrees: base64.b64decode('QQ=Q', validate=True) raises. base32 is affected too (base32pad.decode('ca=aa') returns [0x08, 0x00]).

Root cause: createAlphabetIdx in src/bases/base.ts also indexes the trailing = of the padded alphabets, giving it a symbol value; decode strips only trailing =, so an interior = passes the unknown-character check and is folded in as data.

Fix: skip = when building the alphabet index. Trailing padding is already handled by the strip loop in decode and the pad flag in encode, so any non-trailing = is now rejected as a non-base character. Added a test that round-trips valid input and rejects a spliced interior =; all valid inputs still round-trip.

The padded codecs (base64pad, base64urlpad, base32pad, base32hexpad and the
upper variants) accepted a '=' in the middle of a string and decoded it to
bogus bytes instead of rejecting it. createAlphabetIdx indexed the trailing '='
of the padded alphabets, giving it a symbol value, and decode strips only
trailing '=', so an interior '=' was folded into the output as data.

Skip '=' when building the alphabet index. Trailing padding is handled by the
strip loop in decode and the pad flag in encode, so any non-trailing '=' is now
rejected as a non-base character. Valid input round-trips unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant