DEV Community

Cover image for I Discovered Why "Stripping Metadata" From Images is Security Theater 🎭
Raviteja Nekkalapu
Raviteja Nekkalapu

Posted on

I Discovered Why "Stripping Metadata" From Images is Security Theater 🎭

TL;DR: I spent 3 months researching image-based attacks after a security incident. What I found was alarming: standard "metadata stripping" does almost nothing against modern threats. The only mathematical guarantee of safety is completely destroying and rebuilding the image from scratch.


The Incident That Started Everything

Last year, a friend's startup got hacked. The attack vector? A user's profile picture.

Not a PDF. Not an executable. A simple JPEG uploaded through their avatar picker.

The file passed every standard check:

  • ✅ File extension: .jpg
  • ✅ MIME type: image/jpeg
  • ✅ Magic bytes: Valid (FF D8 FF...)
  • ✅ Antivirus: Clean
  • ✅ Metadata stripped with ExifTool

They were still compromised.

I spent the next three months going down the rabbit hole of polyglots and steganography. What I found changed how I handle user uploads forever.


🚨 The 3 Image Attacks That Bypass "Sanitization"

1. Polyglot Files — The Shape-Shifters

A polyglot is a file that is valid in multiple formats simultaneously.

One common attack is a Phar-JPEG Polyglot:

[Valid JPEG Header] + [Valid PHP Payload] + [Valid JPEG Footer]
Enter fullscreen mode Exit fullscreen mode

To your image upload filter? It looks like a perfectly valid image. To a backend process triggering a filesystem function (like a phar:// wrapper exploit or LFI vulnerability)? It executes as code.

The Reality: Standard sanitizers usually just check headers or strip EXIF tags. They often leave the file structure intact, meaning the malicious payload survives the "cleaning" process.


2. Steganography — Invisible Data Smuggling

We often think of steganography as spy-movie stuff, but it's becoming a standard tool for APTs (Advanced Persistent Threats).

Attackers hide encrypted command-and-control (C2) payloads inside the Least Significant Bits (LSB) or specific DCT coefficients of the image.

# Simplified Concept:
# Original pixel:  RGB(100, 150, 200)
# Malicious pixel: RGB(101, 150, 201)  ← Human eye sees no difference
Enter fullscreen mode Exit fullscreen mode

The Danger: Your server acts as a "dead drop." The malware isn't running on your server, but your server is hosting the encrypted payload for other infected machines to download. Antivirus scanners rarely catch this because it looks like random visual noise (entropy).


3. Image Bombs — The Memory Killer

Also called "decompression bombs." A 50KB PNG file can be crafted to expand into 50GB of raw pixel data when decoded.

If your backend blindly decodes this to process a thumbnail:

1. Upload 50KB file (bypasses size limit)
2. Decoder attempts to allocate 50GB RAM
3. OOM Killer crashes your service
Enter fullscreen mode Exit fullscreen mode

Stripping metadata often triggers this because the stripper has to parse the file first.


💡 The "Aha" Moment: Trust Nothing. Rebuild Everything.

After researching this, I realized the industry standard ("Sanitization") is fundamentally flawed.

Traditional security asks: "Is this file safe?"

This is the wrong question.

The right question is:

"How can we guarantee this file is sterile?"

The answer is Content Disarm and Reconstruction (CDR).

Instead of looking for "bad" things to remove, you extract the one thing you know is "good"—the pixels—and throw everything else away.

The Logic:

  1. Decode the image to a raw buffer (RGBA).
  2. Destroy the original container (headers, metadata, hidden scripts, polyglot payloads).
  3. Re-encode the pixels into a brand new, sterile PNG container.

If the original file had a PHP script hidden in the footer? Gone.

If it had GPS data? Gone.

If it was a malformed buffer overflow attack? Neutralized during decode.


🛡️ Building a Public Solution

I wanted to implement this "Reconstruction" pattern for my own projects, but I hit a wall.

Existing enterprise CDR tools were gated behind "Contact Sales" forms and $15k/year contracts. Open-source tools like ImageMagick have a scary history of CVEs (like ImageTragick), making them risky to run on your own backend.

So, I decided to engineer a dedicated microservice for it.

I built Zero Trust API using Rust and WebAssembly.

Why Rust/WASM?

I needed memory safety. Handling untrusted binary data in C/C++ is a recipe for disaster. By running the decoding logic in a sandboxed WASM environment with strict memory limits, we can process hostile images without risking the host server.

The Architecture:

Input:   Any image (JPG, PNG, WEBP, GIF)
           │
           ▼
Process: Decodes to raw pixels → Destroys container → Rebuilds as sterile PNG
           │
           ▼
Output:  A mathematically generated new file
Enter fullscreen mode Exit fullscreen mode

For the Community

I built this primarily to solve my own headache, but I've opened it up as a public API.

I hate "Contact Sales" buttons, so I made a free tier that's generous enough for most indie projects and dev testing.

If you are handling user-uploaded avatars, KYC docs, or product photos, I highly recommend looking into CDR (whether you use my tool or build your own implementation).

Stop "cleaning" files. Start rebuilding them.


Links for the curious:


Let me know if you've ever encountered these "polyglot" files in the wild. I'm still fascinated by how easily they bypass standard WAFs. 👇

Top comments (2)

Collapse
 
pooja_po profile image
pooja

This is a game-changer for app security! Stripping hidden threats at the pixel level is next-level protection most devs don’t even think about. Really curious to see how this impacts adoption—definitely checking it out!

Collapse
 
ra_vi_51d9667e07aa0984631 profile image
Raviteja Nekkalapu

Super appreciate the kind words! You're right that most devs don't think about this — I didn't either until I needed it for my own project and realized nothing like this existed as an API.

The Rust/WASM core runs in a sandbox, so it's both fast and isolated. Would love to hear your thoughts after you try it.