MD5 has been around since 1991, and despite being broken for cryptographic purposes for nearly two decades, it refuses to die. You'll still find it in file integrity checks, cache keys, ETags, and legacy databases. Knowing when it's harmless and when it's a liability is a genuinely useful skill.

What MD5 actually is

MD5 (Message-Digest Algorithm 5) is a hash function that takes an input of any length and produces a fixed 128-bit output, usually written as a 32-character hexadecimal string. The same input always yields the same output, and even a tiny change in the input produces a completely different hash.

Here's what that looks like:

md5("hello")        = 5d41402abc4b2a76b9719d911017c592
md5("hello.")       = 27fbe7bf80cb6b7d2a11ecc86e9e39e5
md5("Hello")        = 8b1a9953c4611296a827abf8c47804d7

Notice how adding a single period or changing one letter's case scrambles the entire result. That property — the avalanche effect — is what makes hashes useful for detecting change.

Where MD5 is still fine to use

The key distinction: is an attacker involved? If not, MD5 is often perfectly reasonable and fast.

  • Cache keys. Hashing a long query string or a set of parameters into a short, fixed-length key is a classic use. Nobody's attacking your Redis keys.
  • Deduplication. Spotting duplicate files or records by comparing hashes instead of full contents.
  • Checksums for non-security integrity. Verifying a download wasn't accidentally corrupted in transit. Note: this protects against accidents, not tampering.
  • ETags and change detection. Cheap way to tell if a resource has changed since the last request.

In all of these, you care about "did this data change by accident?" not "could someone deliberately forge this?" MD5 handles the first question well and is extremely fast.

Where MD5 will get you in trouble

Never use it for passwords

This is the big one. MD5 is fast, and fast is exactly wrong for password storage. A modern GPU can compute billions of MD5 hashes per second, which makes brute-forcing trivial. Use bcrypt, scrypt, or argon2 instead — they're deliberately slow and salted. If you inherit a system storing MD5 password hashes, treat it as a security incident, not a quirk.

Collisions are real and practical

MD5 is not collision-resistant. Researchers have produced two different files that share the same MD5 hash, and it can be done in seconds on a laptop. That means MD5 is useless anywhere a malicious party could benefit from two inputs matching:

  • Digital signatures
  • SSL/TLS certificates (this is how the Flame malware forged a Microsoft cert)
  • Verifying downloads against a hash an attacker could have swapped

For integrity that must resist tampering, reach for SHA-256 or SHA-3.

Don't confuse hashing with encryption

Hashing is one-way. You cannot "decrypt" an MD5 hash back to the original. What people call "MD5 decryption" is really just lookup tables (rainbow tables) of precomputed hashes for common inputs. That's exactly why unsalted MD5 for anything sensitive is dangerous — common values are already in those tables.

A short worked example

Say you're building a cache and want a stable key from a URL plus some options. In Node.js:

const crypto = require('crypto');

function cacheKey(url, options) {
  const raw = url + JSON.stringify(options);
  return crypto.createHash('md5').update(raw).digest('hex');
}

cacheKey('/api/users', { page: 2, sort: 'name' });
// => '3f8a1c...' (32 hex chars, always the same for the same input)

In Python it's just as short:

import hashlib

def cache_key(url, options):
    raw = url + str(options)
    return hashlib.md5(raw.encode()).hexdigest()

Both give you a compact, deterministic key. The moment any input changes, the key changes, so stale data naturally falls out of the cache. This is a great fit for MD5 — no attacker, just speed and consistency.

When you just need to hash a string quickly to check a value or debug why two cache keys differ, a browser-based MD5 Hash Generator saves you from firing up a REPL. Paste the text, get the hash, compare.

Common gotchas that trip people up

  • Encoding matters. Hashing a UTF-8 string and a UTF-16 version of the same text gives different results. Always be explicit about encoding, especially when comparing hashes generated in different languages.
  • Whitespace and line endings. A trailing newline or a Windows \r\n versus Unix \n will change the hash. If you're comparing file hashes across platforms, normalize first.
  • Uppercase vs lowercase hex. Some tools output ABC123, others abc123. They represent the same bytes, but a naive string comparison will say they don't match. Normalize case before comparing.
  • Truncating the hash. Tempting for shorter keys, but truncation dramatically increases collision odds. If you need short IDs and collisions matter, don't just chop the string.

Quick decision guide

Before reaching for MD5, ask one question: could an adversary gain something by producing a matching hash?

  • No adversary (cache keys, dedup, accidental-corruption checks) → MD5 is fine and fast.
  • Adversary possible (signatures, download verification, certificates) → use SHA-256 or better.
  • Passwords or secrets → use argon2, bcrypt, or scrypt with a salt. Never a general-purpose hash.

MD5 isn't evil — it's a tool that was misapplied for years. Used for what it's actually good at, it's still a perfectly practical part of a working developer's toolkit. Just keep it far away from anything a bad actor might want to break.

Photo by Chris Ried on Unsplash