FileDummy Logo
FileDummy
File Security & Integrity

File Type Validation with Magic Bytes (Not File Extension)

Detect true file types using magic bytes in Node.js with the file-type library. Extension-based validation is trivially bypassed β€” learn the secure approach.

September 26, 20269 min read1,420 views
nodejssecuritymagic-bytesmime-typevalidation

Relying solely on file extensions (like .pdf or .jpg) or the client-supplied Content-Type header is dangerous. An attacker can easily rename malware.exe to invoice.pdf and bypass standard filters. True file validation requires inspecting magic bytes.

What Are Magic Bytes?

Magic bytes (file signatures) are specific hexadecimal byte sequences located at the exact beginning of a file:

File FormatExtensionMagic Bytes (Hex)ASCII Representation
PDF.pdf25 50 44 46%PDF
PNG.png89 50 4E 47.PNG
JPEG.jpgFF D8 FFÿØÿ
ZIP / DOCX.zip/.docx50 4B 03 04PK..
GIF.gif47 49 46 38GIF8
Verified Test Asset.docx

Download a real 1MB DOCX file to inspect its PK ZIP container magic bytes in your code.

Download 1MB DOCX Sample β†’

Detecting Magic Bytes in Node.js with file-type

Terminal
npm install file-type
TypeScript
import { fileTypeFromBuffer } from 'file-type';

export async function validateActualFileType(buffer: Buffer, expectedMime: string): Promise<boolean> {
  const detected = await fileTypeFromBuffer(buffer);

  if (!detected) {
    console.error('Unknown or unsupported binary structure.');
    return false;
  }

  console.log(`Detected true format: ${detected.ext} (${detected.mime})`);
  return detected.mime === expectedMime;
}

Reading Magic Bytes in the Browser

You can read the first 16 bytes of any File or Blob without loading the whole file into RAM:

TypeScript
export async function checkPdfHeaderInBrowser(file: File): Promise<boolean> {
  const headerBlob = file.slice(0, 4);
  const arrayBuffer = await headerBlob.arrayBuffer();
  const bytes = new Uint8Array(arrayBuffer);

  // %PDF in ASCII is [0x25, 0x50, 0x44, 0x46]
  return bytes[0] === 0x25 && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46;
}

Security Gotchas

  • Polyglot files: Files crafted to be simultaneously valid JPEGs and executable scripts. Always pair magic byte validation with format re-encoding or sandboxed processing.
  • DOCX/XLSX detection: Office documents are ZIP archives. Their magic bytes will report as application/zip. Use an OpenXML validator to check for word/document.xml inside the archive.
NDL

Nguyen Dai Long

Author

Backend Lead β€’ Distributed Systems & Cloud Edge Architecture Specialist

4+ years designing high-throughput file ingestion pipelines, database architectures, and distributed edge storage on Cloudflare R2 & AWS S3. Founder of FileDummy and the NDL Ecosystem.

Was this article helpful?

Click Like to support the author and help other developers discover this guide.

Engineering Discussion & Feedback (0)

Share benchmark results, report edge cases, or ask technical questions.

0/3000

No comments yet. Be the first developer to start the discussion!

Frequently Asked Questions

What are magic bytes?β–Ύ

Magic bytes are the first few bytes of a file that uniquely identify its format. PDF starts with 25 50 44 46 (%PDF), ZIP/DOCX with 50 4B 03 04 (PK..), JPEG with FF D8 FF, PNG with 89 50 4E 47. The file-type library uses these signatures to detect true format regardless of extension.

Why is extension-based validation dangerous?β–Ύ

An attacker can rename malware.exe to document.pdf and bypass extension checks. Operating systems determine file type from content, not filename. Always validate actual bytes using file-type (Node.js) or Apache Tika (Java).

Can I detect file types in the browser?β–Ύ

Yes. Read the first 12 bytes using FileReader.readAsArrayBuffer() on a Blob.slice(0, 12), then check against known signatures. The file-type library also works in browser environments.

Related Articles