Base64 in HTTP Headers: Pitfalls and Fixes

·6 min read·base64httpencoding

Line breaks, padding characters, URL-safe variants, and the persistent myth that Base64 is a form of encryption. What to watch for when you move binary data over text protocols.

Base64 exists because text protocols — email, HTTP headers, JSON, URLs — are historically uncomfortable with arbitrary bytes. You cannot put a raw binary blob into a Set-Cookie value or an Authorization header and expect it to survive the trip. Base64 solves this by mapping every three bytes to four printable ASCII characters chosen from a 64-symbol alphabet. The result is larger, but it passes through every text-oriented system unchanged. Most of the time.

Padding

Base64 encodes 3 bytes into 4 characters. If your input length is not a multiple of 3, the encoder pads the output with one or two = characters so the output length is always a multiple of 4. Two bytes become three characters plus one =. One byte becomes two characters plus two ==.

A common bug: a library that strips padding on encode but refuses to decode unpadded input. The moment a strict decoder meets a relaxed encoder (or vice versa) you get a runtime error. Most modern libraries have an option to ignore missing padding; turn it on for external input.

URL-safe Base64

The standard Base64 alphabet includes + and /. Both are meaningful inside URLs — + is sometimes interpreted as a space in query strings, and / is a path separator. URL-safe Base64 (RFC 4648 §5) swaps these for - and _ so the encoded string survives being stuffed into a URL without further escaping.

JWTs use URL-safe Base64 (specifically "Base64url"), typically without padding. A token segment with -and _ characters and no trailing = is not malformed; it is the spec.

Line breaks

MIME Base64, defined for email, wraps lines at 76 characters with \r\n. HTTP Base64 does not. If you paste a Base64 blob out of an email or a PEM certificate into an HTTP-style decoder, it may fail unless the decoder is tolerant of whitespace. PEM files wrap at 64 characters, by the way, not 76 — a different spec, same problem.

If you are writing a parser, allow whitespace. If you are writing a signer, do not insert whitespace that the verifier will have to strip — it is an easy source of "works on my machine" bugs.

Base64 is not encryption

This deserves its own heading because it is one of the most persistent misconceptions in software. Base64 is areversible encoding: anyone who has the output can trivially compute the original input. There is no key.

If you Base64-encode a secret, the secret is now a slightly longer, slightly less readable string — and it is still plaintext to anyone who sees it. If you want confidentiality, you want encryption. If you want integrity, you want a MAC or a signature. Base64 provides neither.

Binary in JSON

JSON strings are Unicode, not bytes. To embed a binary payload (an image thumbnail, a compressed blob, a nonce) inside a JSON document, Base64 is the standard answer. The cost is ~33% size inflation: 3 bytes of input become 4 characters of output, and each character is (in UTF-8) at least 1 byte.

For large payloads, consider whether the blob belongs in the JSON at all. A data URL or a content-addressed reference to separate storage is often cheaper than shipping megabytes of Base64 through your API.

Decoding untrusted input

If an attacker controls the Base64 input to your decoder, they control the bytes that come out. Sanitize the decodedvalue the same way you would sanitize any other user input — check its length, validate its structure, and do not interpret it as a file path or a serialized object without further checks.

Decoders themselves are generally not a security risk, but the things you do with the decoded bytes can be. A surprising number of "deserialize this Base64 payload" APIs turn out to allow remote code execution via a crafted payload, because the deserializer trusts its input.

Try it on ToolPad

The Base64 Encode / Decode tool handles standard Base64 in the browser. It is useful for inspecting values out of Authorization: Basic ...headers, for decoding the payload of a PEM-less certificate, or for prepping a binary blob to paste into a test fixture. Everything runs locally; your input stays on your device.

For JWT tokens specifically, the JWT Decoder handles Base64url and the three-segment split for you.