A File Doesn't Know What Kind of File It Is
Take a JPEG named photo.jpg. Duplicate it, rename the copy to photo.zip, and compare the two files byte for byte.
Nothing inside changed. The first byte is still the first byte of the JPEG. The compressed image data is still where it was. The checksum is identical.
Yet the icon may change. Double-clicking may launch an archive utility instead of an image viewer. An upload form may accept one name and reject the other. One part of the system now behaves as if the file changed, even though the file’s contents did not.
This is the useful ambiguity behind the title. A file can contain strong evidence about its format, but it does not carry one universal field that every program must treat as its true identity. “File type” is the answer to several different questions that software often compresses into one label.
The way out is to stop asking what type is this file? and ask which decision we are trying to make.
The filename answers what should open
An extension is part of a filename. Operating systems and desktop applications use it as a cheap routing signal: .jpg can be associated with an image viewer, while .zip can be associated with an archive utility. Microsoft describes Windows file associations in exactly these terms, and the freedesktop.org shared MIME database keeps mappings from filename patterns alongside rules that inspect content.
That makes extensions useful. Reading a suffix is fast, requires no access to the file body, and usually matches the author’s intent.
It does not make the suffix a property of the bytes.
When we rename photo.jpg to photo.zip, we change the routing hint. We do not turn the JPEG grammar into the ZIP grammar. An archive utility can still try to parse the file and reject it. An image decoder that ignores the name can still display it.
The name therefore answers a practical question: which behavior should the surrounding system try first? It does not prove what structure the file contains.
The laboratory below makes that separation observable. It uses three harmless built-in samples: a valid one-pixel Portable Network Graphics (PNG) image, the exact same bytes given a .zip name and a conflicting media type, and an eight-byte file that contains only the PNG signature. You can also inspect a local file. Nothing is uploaded.
Browser laboratory
File Identity Lab
Compare what is declared, what a prefix recognizer sees, and what a small structural parser can establish.
LOCAL ONLY
Preparing the local analysis…
| Built-in sample | Declared type | Signature | PNG structure |
|---|---|---|---|
one-pixel.png | image/png | PNG | Accepted |
one-pixel.zip | application/zip | PNG | Accepted |
png-header-only.png | image/png | PNG | Rejected |
Scope: this is a teaching instrument, not an antivirus scanner or universal file validator. It recognizes five common signatures and structurally checks only the PNG rules stated above.
The first two samples have the same hash because they have the same bytes. Their declarations differ. The third starts like a PNG but cannot be decoded as one. Those are three distinct statements, not three confidence levels for the same statement.
A media type is a declaration in context
On the web, the next answer often arrives as a media type such as image/png or application/zip. The names are registered by the Internet Assigned Numbers Authority (IANA) , and the registration procedures are defined in Request for Comments (RFC) 6838 .
In Hypertext Transfer Protocol (HTTP), a server sends that declaration in the Content-Type header. RFC 9110 says the field describes both the data format and how the recipient is intended to process it within that message. This is metadata about a representation moving through a protocol. It is not a hidden byte embedded inside every file.
A local browser file has a related but narrower signal. The Web File API exposes File.type, which must be a lowercase parsable media type or an empty string when the user agent cannot determine one. The specification does not promise that the browser fully parsed the file to produce it. In practice, the result can depend on the browser, operating system and filename information available when the File object was created.
That is why the laboratory labels this value browser-supplied type, not detected format. For the built-in renamed sample, the conflicting value is supplied deliberately so that the disagreement remains reproducible on every device.
The distinction matters at upload boundaries. If a client says image/png, it has made a claim. A server can use the claim for routing, but it should not treat user-controlled metadata as proof that a decoder will see a safe image.
A signature recognizes a beginning
If names and declarations can be wrong, inspect the bytes.
Many formats begin with a recognizable pattern, often called a file signature or magic bytes. A PNG datastream starts with these eight bytes:
89 50 4E 47 0D 0A 1A 0AThe current PNG specification explains why the sequence exists. It distinguishes PNG from other datastreams and catches several common transfer errors. The Unix file utility and its libmagic library generalize this idea through a database of byte patterns and structural tests.
Signature matching answers a better question than the extension: does this input begin like a format I recognize?
It still does not answer whether the complete input is valid.
The PNG signature is followed by chunks. A conforming PNG begins with an IHDR header chunk, contains image data in one or more IDAT chunks, and ends with IEND. Each chunk also carries a cyclic redundancy check (CRC) over its type and data. Eight correct bytes followed by nothing satisfy the signature test and fail the format grammar.
That is what the third laboratory sample demonstrates. Calling it “PNG detected” without qualification would turn a prefix match into a claim about the entire file.
Parsing asks whether the structure holds together
To make a stronger claim, a program must follow the format’s structure.
For PNG, that means reading chunk lengths without stepping beyond the available bytes, enforcing the order of critical chunks, checking required fields, validating CRC values and reaching a valid IEND. For ZIP, PDF or an EPUB publication, the relevant structures and constraints are different. There is no universal “parse file” operation detached from a format grammar.
This gives us another separation:
| Layer | What it observes | What it can establish |
|---|---|---|
| Filename | A suffix such as .png | A naming convention or application route |
| Declared media type | Metadata such as image/png | The sender’s intended interpretation in this context |
| Signature match | Selected bytes at known offsets | Compatibility with a recognition rule |
| Structural validation | Relationships across the input | Conformance to the checks that were actually implemented |
| Application behavior | One concrete parser and its surrounding code | What that program accepts and does |
The last two rows are deliberately not identical.
A specification describes a language of valid byte sequences. A parser is an implementation that attempts to recognize or consume that language. Real parsers can support only part of a specification, add extensions, recover damaged inputs, ignore trailing data, impose resource limits or contain bugs. Two programs can therefore receive the same bytes and disagree without either program having “changed” the file.
Sometimes one parser is stricter. Sometimes one is more forgiving. Sometimes they are answering different questions: a thumbnailer may decode the first image it can recover, while an archival validator may reject the same input because one checksum is wrong.
“It opens” is evidence about one application. It is not a proof of universal conformance.
Some bytes satisfy more than one grammar
Up to this point, every mismatch could be explained by a wrong label or an incomplete test. File polyglots introduce a stronger case: one byte sequence can be accepted as two or more formats.
This is possible because format grammars leave different kinds of room. One format may allow comments or ignored fields. Another may locate important structures from the end of the file. A parser may skip bytes that another parser treats as meaningful. If the constraints can coexist, the resulting bytes belong to the intersection of two accepted languages.
That does not mean parsers decide arbitrarily. The opposite is true. A polyglot works because the byte sequence satisfies two sets of rules at once, at least for the implementations under test.
The 2013 paper Polyglots: Crossing Origins by Crossing Formats examined how these multiple interpretations could cross security boundaries on the web. More recent research, On the Abuse and Detection of Polyglot Files , studied real attack chains and found that format-identification tools could miss polyglots used in the wild.
There is an important limit here. A file that one tolerant program partially recovers and another program rejects is not automatically a formal polyglot. Neither is a file merely because a text editor can display its bytes. The meaningful claim is that two relevant parsers accept the same input under two format interpretations.
The laboratory does not generate or distribute a polyglot. We do not need one to establish the article’s central distinction, and a reusable polyglot builder would add risk without adding much understanding.
Ambiguity becomes dangerous when authority changes
A mismatched extension is not a vulnerability by itself. Neither is a signature match, a malformed file or even a polyglot.
The security problem appears when one stage approves an input under one interpretation and a later stage gives it more capability under another.
Imagine an upload pipeline:
- the gate checks the extension and allows images;
- a scanner sees a PNG signature and routes the file to an image-only rule set;
- the server later publishes the original bytes with a scriptable media type;
- a browser or another consumer interprets active content that the first two stages never examined.
The dangerous property is not merely “two types.” It is validation under one grammar followed by use under a more powerful grammar.
Modern systems reduce this gap in layers. They allowlist expected media types, parse with a format-specific decoder, reject unexpected structures, re-encode media when preservation of the original bytes is unnecessary, serve untrusted files from isolated origins, use download-oriented disposition when appropriate, and send accurate Content-Type metadata. On the web, X-Content-Type-Options: nosniff tells the browser to enforce the declared type for destinations where the Fetch standard applies that check.
No single check replaces the others because the checks protect different transitions. Renaming a file does not rewrite its grammar. Matching magic bytes does not validate the body. Successfully decoding an image does not prove that preserving every original byte is safe for every later consumer.
The file type was the wrong object
Return to photo.zip.
Its bytes still conform to whatever JPEG structure they conformed to before the rename. Its new suffix now suggests ZIP. A desktop shell can route it to an archive utility. A browser can attach a media type derived from the information available to it. A signature detector can recognize JPEG. A JPEG decoder may accept it. A ZIP parser should reject it unless the bytes also satisfy ZIP’s rules.
Which answer is the file’s identity?
None is a universal replacement for the others. Each belongs to a relationship:
- a name and a naming convention;
- a message and its declared media type;
- a byte sequence and a recognition rule;
- a byte sequence and a format grammar;
- an input and a concrete parser;
- a parsed result and the behavior an application permits.
The file does not need to know what it is. The system needs to state what it observed, which grammar it checked, and what it plans to do next.
That is a less convenient answer than one type label. It is also the answer that survives a rename.