Skip to main content

Reading a File's Real Type From Its Magic Bytes, Not Its Extension

A renamed .jpg can really be a PNG or worse. Learn how magic bytes reveal a file's true type, why it matters for upload security, and how to inspect files locally.

Published By Li Lei
#file types #magic bytes #mime type #security #file uploads

Reading a File's Real Type From Its Magic Bytes, Not Its Extension

An extension is a label, and labels lie. The .jpg on the end of a filename is just text anyone can type. Rename report.pdf to report.jpg and your file manager will happily show it with a photo icon, but nothing about the file actually changed. The bytes inside are still a PDF. If you build anything that accepts files from other people, that gap between the name and the contents is where a surprising number of bugs and security holes live.

The reliable way to know what a file actually is comes from the file itself. Most formats begin with a short, fixed sequence of bytes called a magic number, or signature. The operating system, browsers, and well-written upload validators all read those first bytes instead of trusting the extension. This post walks through how that works, why a renamed .jpg might really be a PNG, and how to check it yourself without sending the file anywhere.

What Magic Bytes Actually Are

When a format is designed, its authors usually reserve the opening bytes as a recognizable marker. The real type is read from the file's first bytes, the magic number, not the extension, which anyone can rename. A few you'll meet constantly:

  • JPEG starts with FF D8 FF
  • PNG starts with 89 50 4E 47 (the 50 4E 47 part is literally the ASCII letters "PNG")
  • PDF starts with 25 50 44 46, which is %PDF
  • ZIP (and everything built on it, including .docx, .xlsx, .jar) starts with 50 4B, or PK, after the format's creator Phil Katz
  • GIF starts with 47 49 46 38, the text "GIF8"
  • gzip starts with 1F 8B

Notice the pattern. These signatures sit at byte zero and don't move. You don't need to parse the whole file or understand its internal structure to identify it; you read maybe the first 16 bytes and compare them against a table. That is exactly how file on Unix, the Content-Type sniffing in browsers, and serious upload validators all decide what they're holding. This is also how you safely validate an upload: you check the magic bytes, not the name the client claimed.

Why a Renamed .jpg Might Really Be a PNG

Here's a worked example you can reproduce. Take a normal screenshot, which your system saved as screenshot.png. Rename it on disk to screenshot.jpg. Drag it into an inspector and look at what comes back:

  • Filename: screenshot.jpg
  • Extension: jpg
  • First bytes (hex): 89 50 4E 47 0D 0A 1A 0A
  • Magic signature: PNG

The extension says JPEG. The first bytes say 89 50 4E 47, which is the unmistakable PNG signature. They disagree, and the magic bytes win, because they describe the data that's really there. A program that decodes this file as JPEG because of the .jpg will either error out or produce garbage. A program that reads the magic bytes knows to hand it to a PNG decoder.

This is not just a curiosity. Attackers rename files on purpose. A .jpg that is really a ZIP archive, a Windows executable (MZ, or 4D 5A), or an HTML file with a script in it is a classic way to slip past a naive upload filter that only checks the extension or trusts the browser-supplied MIME type. If your "image uploader" stores whatever bytes it's handed and serves them back later, a renamed payload can become a stored cross-site scripting bug or worse. Reading the signature closes that specific door.

Three Signals, Three Sources

It helps to keep three separate pieces of information distinct, because each comes from a different place and each can be wrong in its own way:

  1. Extension comes from the filename. Free for anyone to set. Zero guarantee.
  2. Browser MIME type comes from the operating system's metadata about the file. Often right, sometimes blank, occasionally wrong, and never something you should trust as your only check on the server side.
  3. Magic signature comes from the actual bytes. For common binary formats it's the most reliable of the three.

When all three agree, you can relax. When they disagree, the magic bytes are usually telling the truth and the other two are telling you something got mislabeled somewhere upstream. The File MIME Type Inspector shows all three side by side so you can spot the mismatch at a glance instead of guessing. If you then need to map a confirmed type to its canonical media type string, the MIME type lookup goes the other direction, from extension or format name to the registered Content-Type.

Inspection Stays On Your Machine

One thing worth being explicit about: this kind of inspection should never require uploading the file. Reading the first bytes of a file is cheap and entirely local. A browser can open the file you select, read its leading bytes, compare them against a signature table, and print the result without a single network request. The file never leaves your machine. That matters when the "mystery attachment" you're inspecting came from a support ticket, a compliance review, or a security incident, where shipping an unknown file off to a third-party server is exactly the wrong move.

I lean on this habit more than I expected to. The first time it earned its keep for me was a vendor data export that a colleague's importer kept rejecting with a uselessly generic "invalid file" message. Everyone assumed the importer was broken. I dropped the file into a local inspector and the magic bytes read 50 4B 03 04, a ZIP, even though the file was named export.csv. The vendor had zipped the CSV and never changed the extension. Two minutes of looking at bytes settled an argument that had been bouncing around a chat thread for half a day.

Putting It to Work

Once you can see the real type, a few common tasks get easier:

  • Validating uploads: decide what you accept based on the signature, not the name. Build an allowlist of magic numbers for the formats you actually support and reject everything else, regardless of what the extension or browser MIME type claims.
  • Triaging unknown attachments: when a file comes in with no extension or a wrong one, the signature tells you whether you're looking at an image, an archive, a document, or something that wants a closer look. Export an evidence table and move on.
  • Encoding and round-tripping: when you need to move a binary file through a text-only channel, the file to Base64 converter turns it into a safe text blob, and you can confirm what you started with before encoding.

A caution worth repeating: a magic-byte check is a signature match, not a malware scan. It tells you what format a file claims to be, which is enough to catch mislabeling and block the obvious renamed-payload trick, but it does not tell you the contents are safe. Some text-based formats also have weak or absent signatures, so an "unknown" result means inconclusive, not clean. For high-risk files, treat the inspector as a first triage step and follow up with a proper forensic or scanning tool.

The short version: stop trusting the name on the end of the file. Read the first bytes, let the magic number tell you the truth, and make your decisions from there.


Made by Toolora · Updated 2026-06-13