base64.b64decode() Silently Strips Invalid Characters by Default (tested)
base64.b64decode() looks like it should reject malformed input. We measured what happens when a base64 string has extra, invalid characters injected into it -- the default call doesn't just tolerate them, it silently discards them and returns a result as if nothing was wrong.
1. Injected invalid characters are silently discarded, not rejected
import base64
good = base64.b64encode(b"hello world").decode()
corrupted = good[:4] + "!!!!" + good[4:]
print(corrupted)
print(base64.b64decode(corrupted))
aGVs!!!!bG8gd29ybGQ=
b'hello world'
Measured: four extra ! characters, which are not part of the base64 alphabet, were spliced into the middle of a valid encoded string. base64.b64decode() still returns the exact correct original bytes -- it simply throws away any character that isn't valid base64 before decoding, with no error, no warning, and no way to tell from the return value that the input was ever tampered with.
2. validate=True makes it reject the same input
import base64
corrupted = "aGVs!!!!bG8gd29ybGQ="
print(base64.b64decode(corrupted, validate=True))
Traceback (most recent call last):
...
binascii.Error: Only base64 data is allowed
Measured: the exact same corrupted string raises binascii.Error once validate=True is passed. This single keyword argument is the entire difference between silently accepting tampered or corrupted input and correctly rejecting it. validate defaults to False, so every call site that doesn't explicitly opt in is exposed to this -- a realistic risk anywhere base64 arrives from outside your program: URL parameters, custom headers, or a token that's been partially mangled by an intermediary.
3. Missing padding is the one thing that does raise, by default
import base64
good = base64.b64encode(b"hello world").decode()
nopad = good.rstrip("=")
print(base64.b64decode(nopad))
Traceback (most recent call last):
...
binascii.Error: Incorrect padding
Measured: removing the trailing = padding raises binascii.Error: Incorrect padding even with the default validate=False. So the function already fails loud on one class of malformed input (wrong length/padding) but silently tolerates another, arguably worse, class (wrong characters) unless you explicitly pass validate=True. If you're decoding anything that didn't originate from your own b64encode() call, pass validate=True and handle the resulting binascii.Error.
Frequently asked questions
Does base64.b64decode() validate its input by default?
Partially -- we measured this: it raises binascii.Error for incorrect padding (wrong length), but silently discards any character outside the base64 alphabet instead of raising, unless you pass validate=True.
How do I make Python's base64 decoder reject invalid characters?
Pass validate=True to base64.b64decode(). We confirmed the exact same corrupted input that decodes silently with the default settings raises binascii.Error('Only base64 data is allowed') once validate=True is set.
Can corrupted or tampered base64 data decode successfully in Python?
Yes -- we measured this directly: splicing extra, invalid characters into a valid base64 string and decoding it with the default settings returned the correct original bytes with no error at all, since the invalid characters were just dropped before decoding.
Why does base64.b64decode() raise an error for missing padding but not for invalid characters?
These are different checks implemented separately: padding length is always validated, but character-set validation is optional and off by default. We confirmed both behaviors on the same input by toggling only the validate argument.
Should I always pass validate=True when decoding base64 from external input?
Yes, for anything not produced by your own code -- we confirmed the default (validate=False) will silently accept and decode input that's been corrupted or tampered with, which can hide a real problem with the data's source or integrity.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in base64 module: encoded a known string, inserted invalid (non-base64-alphabet) characters into the middle of it, then decoded with base64.b64decode()'s default validate=False versus validate=True, and separately measured what happens with missing padding. PlainHeaders is our extension; Python's base64 module is built in.