Upload a file
  1. base64hub
  2. Learn Base64
  3. Common Base64 prefixes
Reference

Common Base64 Prefixes: Identify a File by Its Start

Most file formats begin with fixed magic bytes, so their Base64 begins with fixed characters too. Learn a dozen prefixes and you can tell a PNG from a PDF before decoding anything.

Prefix table

Each row was checked by encoding the real magic bytes of the format. “Stable prefix” is the part that never changes for that format. The characters after it depend on the rest of the file.

Base64 prefixMagic bytes (hex)FormatOpen with
iVBORw0KGgo89 50 4E 47 0D 0A 1A 0APNGBase64 to PNG
/9j/FF D8 FFJPEGBase64 to JPG
R0lGOD47 49 46 38 (GIF8)GIF (R0lGODlh = GIF89a, R0lGODdh = GIF87a)Base64 to GIF
UklGR52 49 46 46 (RIFF)WebP, WAV, AVIBase64 to WebP, Base64 to WAV
JVBERi025 50 44 46 2D (%PDF-)PDFBase64 to PDF
UEsDB50 4B 03 04 (PK..)ZIP, DOCX, XLSX, PPTX, JAR, APK, EPUBBase64 to ZIP, Word, Excel
H4sI1F 8B 08gzipDecode gzip Base64
eJ, eN, eF, eA78 9C, 78 DA, 78 5E, 78 01zlibZlib and Base64
eyJ7B 22 ({")JSON object, JWTBase64 to JSON, JWT decoder
PD94bWwg3C 3F 78 6D 6C 20 (<?xml )XML, SVG with declarationBase64 to XML
PHN2Zy3C 73 76 67 20 (<svg )SVG without declaration (<svg plus a newline gives PHN2Zw)Base64 to SVG
MII30 82DER: certificates, keys, CSRscertificate decoder
AAAA00 00 00SSH public key blob, or leading zerosSSH key fingerprint
SUQz49 44 33 (ID3)MP3 with ID3v2 tagBase64 to MP3
AAABAA00 00 01 00ICOBase64 to ICO
d09GMg77 4F 46 32 00 (wOF2)WOFF2 font with TrueType outlines (CFF fonts start d09GMk9UVE8)Base64 to font
TVqQ4D 5A 90 (MZ)Windows EXE or DLL (some linkers write MZP, which gives TVpQ)Base64 to file
f0VMR7F 45 4C 46 (.ELF)Linux ELF binaryBase64 to file

A few rows deserve a note:

  • RIFF is a container. The format name sits at bytes 8 to 11, and bytes 9 to 11 encode as the 13th to 16th characters: RUJQ for WebP (EBP), QVZF for WAV (AVE), Vkkg for AVI (VI ). The first letter of the format name shares a 3-byte group with the file size, so it does not produce a stable character.
  • zlib has no single prefix. The second byte records the compression level: eJ for the default level, eN for levels 7 to 9, eF for 2 to 5, eA for 0 and 1 (as written by Python’s zlib).
  • JSON starts with eyJ only when the first two characters are {" with no space. { "a": 1 } starts with eyAi, pretty-printed { plus a newline starts with ewo, and an array [ starts with W.
  • DER structures start with a SEQUENCE tag 30, which always gives M. A two-byte length (30 82) gives MII, and the next character tracks the length: an RSA 2048 public key is MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA, a typical certificate is MIIC, MIID or MIIE. Short structures use a one-byte length: an Ed25519 private key starts with MC4C, a P-256 public key with MFkw.
  • SSH public keys begin with a 4-byte big-endian length, so the blob starts with AAAA. The next characters spell the key type: AAAAC3NzaC1lZDI1NTE5 is ssh-ed25519, AAAAB3NzaC1yc2E is ssh-rsa, AAAAE2VjZHNh is ecdsa. Outside SSH, a run of A means zero bytes.
  • MP3 files without an ID3 tag start directly with a frame header. Its sync bits FF Fx give a leading //, for example //uQ for FF FB 90.
  • Base64URL replaces + and /, so the JPEG prefix becomes _9j_. The other prefixes in the table contain neither character and look the same in both alphabets.

Why the prefix is stable

Base64 works on groups of 3 bytes. Each group of 3 bytes becomes exactly 4 characters, and those 4 characters depend only on those 3 bytes. Nothing from later in the file leaks backwards. So if a format always starts with the same 3 bytes, its Base64 always starts with the same 4 characters.

bytes:   FF       D8       FF
bits:    11111111 11011000 11111111
groups:  111111 111101 100011 111111
index:   63     61     35     63
chars:   /      9      j      /

When the fixed magic is not a multiple of 3 bytes long, the last group mixes known bits with bits from the rest of the file. Take the 5-byte %PDF-. The first 3 bytes give 4 stable characters (JVBE). The next 2 bytes give 2 more (Ri), and the seventh character mixes the last 4 bits of - with the first 2 bits of the version digit. Every digit starts with the bits 00, so in practice that character is always 0. After JVBERi0 the version shows through: JVBERi0xLjQ is %PDF-1.4, JVBERi0xLjc is %PDF-1.7, JVBERi0yLjA is %PDF-2.0.

The PNG signature is 8 bytes, which gives 10 stable characters. The eleventh mixes the last signature byte with the first byte of the IHDR chunk length, which is always 0, so iVBORw0KGgo holds. Since every PNG continues with that IHDR chunk, real PNGs share an even longer prefix: iVBORw0KGgoAAAANSUhEUg.

When the prefix shifts

The prefix only works when the magic bytes sit at offset 0, 3, 6 and so on. Add one byte in front and every group shifts, so the characters change completely:

InputBase64 starts with
PNG signatureiVBORw0KGgoAAAA
1 byte + PNG signatureAIlQTkcNChoKAAAA
2 bytes + PNG signatureAACJUE5HDQoaCgAA
3 bytes + PNG signatureAAAAiVBORw0KGgoA

With 3 extra bytes the alignment is restored and the familiar prefix reappears 4 characters later. Common reasons for a shifted or missing prefix:

  • A byte order mark. UTF-8 text with a BOM starts with 77u/ (EF BB BF). The BOM is 3 bytes, so JSON after it still shows eyJ: 77u/eyJ…. UTF-16 text with a BOM starts with //4 or //5 (little-endian) or /v8 (big-endian).
  • UTF-16 text. Text saved as UTF-16LE puts a zero byte after every ASCII character, which produces a lot of A: Hello becomes SABlAGwAbABvAA==. PowerShell’s -EncodedCommand looks like this. Use the PowerShell decoder or Base64 to UTF-16.
  • Compression or encryption. A gzipped PNG starts with H4sI; an encrypted file has no recognizable prefix at all.
  • A data URI. data:image/png;base64, is a header; the Base64 starts after the comma. The data URI parser splits them for you.
  • Line breaks and whitespace. They do not shift the bytes, but a prefix search with startswith will fail if the string begins with a newline or a quote. Trim first, or run it through Repair Base64.

Checking a prefix in code

You can match the first characters as strings, but comparing decoded bytes is less error-prone: the magic numbers come straight from each format’s specification, and you never have to work out which characters are stable. Decoding only the first 12 characters gives the first 9 bytes, enough for most signatures:

import base64

SIGNATURES = {
    b"\x89PNG\r\n\x1a\n": "png",
    b"\xff\xd8\xff": "jpeg",
    b"%PDF-": "pdf",
    b"PK\x03\x04": "zip",
    b"\x1f\x8b": "gzip",
}

def sniff(b64: str) -> str:
    head = base64.b64decode(b64.strip()[:12])
    for magic, name in SIGNATURES.items():
        if head.startswith(magic):
            return name
    return "unknown"

print(sniff("iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB"))  # png
print(sniff("JVBERi0xLjcKJcfsj6IK"))              # pdf

The Base64 to file tool does the same check against a longer list and shows a preview when the browser can render the format. For how the 6-bit groups map to characters, see how Base64 works and the alphabet table.

FAQ

What does a Base64 string starting with iVBORw0KGgo mean?

It is a PNG image. iVBORw0KGgo is the Base64 form of the 8-byte PNG signature 89 50 4E 47 0D 0A 1A 0A. Paste it into Base64 to PNG to see it.

What is /9j/ at the start of a Base64 string?

A JPEG. The bytes FF D8 FF that open every JPEG file encode to /9j/. In Base64URL the same prefix is written _9j_.

Why do JWTs always start with eyJ?

A JWT header is a JSON object, so it begins with {", and those two bytes encode to eyJ. The payload part starts with eyJ for the same reason.

My Base64 does not match any known prefix. What now?

The data may have extra bytes in front, be compressed or encrypted, or be plain text. The Base64 to file tool decodes the data and checks the bytes against many signatures.

Keep reading