The idea: protect sensitive data in transit and at rest
Cryptographic failures (OWASP Top 10:2025, A04) are what happens when sensitive data — passwords, session tokens, personal and payment data — is not protected with the right cryptography, or with any at all. The failure is rarely a broken algorithm; it is almost always a use mistake: data sent in the clear, a password stored with a fast unsalted hash, a cipher used in a mode that leaks structure, a key committed to a repository, or a secret token generated so predictably that it can be guessed.
This page runs five such mistakes against a fictional shop, shop.example, with users alice, carol (who both pick the password password1) and bob. The attacker is mallory. The core control is a vulnerable vs fixed switch: each scenario runs the same attack against the vulnerable app, then against the fixed app, so you can see exactly which control stops it. Every hash, ciphertext, key and token on the page is a short, deterministic fake value — the page teaches the ideas, it is not a working tool.
Common CWEs behind A04: CWE-319 (cleartext transmission), CWE-327 (broken or risky crypto algorithm or mode), CWE-328 (use of a weak hash), CWE-916 (password hash without enough computational effort / no salt), CWE-321 (use of a hard-coded cryptographic key) and CWE-330 (use of insufficiently random values).
Data in transit: TLS and HSTS
On open Wi-Fi anyone nearby can read every packet. If the login goes over http://, the request body password=password1 crosses the air as readable text and mallory simply copies it (Demo 1, vulnerable). The fix is to serve the whole site over TLS (https://): the browser encrypts the request into a TLS record before it leaves the device, so the capture holds only ciphertext. HSTS (Strict-Transport-Security) tells the browser to never even try plain HTTP again, closing the downgrade window. That is CWE-319.
Password storage: salt and a slow hash
Databases leak. What matters is what the users table stored. Unsalted MD5 is fast and salt-free, so two problems appear at once (Demo 2, vulnerable): alice and carol show the same hash 7c6a180b, which already reveals that they share a password (CWE-916); and because the hash is fast and unsalted, a precomputed rainbow table maps it straight back to password1 in a single lookup (CWE-328).
The fix is a slow password hash with a per-user salt and a tunable cost: bcrypt or argon2id. A bcrypt hash carries its parameters and salt inline, $2b$12$<22-char salt><hash>; the 12 means 212 rounds per guess. Now alice and carol get different hashes despite the same password (the salt differs), rainbow tables are useless, and each brute-force guess is thousands of times slower.
Cipher mode: ECB vs GCM
AES is a strong cipher, but the mode that chains its blocks decides whether patterns survive. ECB encrypts each 16-byte block independently with the same key, so identical plaintext blocks become identical ciphertext blocks (Demo 3, vulnerable): here blocks B1, B2 and B4 are equal, and the ciphertext repeats AB12 in the same places. mallory never decrypts anything, yet the layout of the data leaks — the famous "ECB penguin" (CWE-327).
An authenticated mode such as AES-GCM mixes a fresh random nonce and the block position into the keystream, so identical plaintext blocks encrypt to different ciphertext and no structure shows. GCM also produces an authentication tag that detects tampering, which ECB and CBC do not.
Keys and secrets
A cipher is only as safe as its key. A key hard-coded in crypto.js and committed to git lives in every clone and every past commit, so anyone who reads the source reads the key and can decrypt and forge everything (Demo 4, vulnerable; CWE-321). Rotating it means editing and redeploying code. The fix is to keep keys out of source entirely: load them at runtime from a secrets manager / KMS / environment, grant them only to the running service, and rotate them centrally. The repository then holds a reference such as kms.get("APP_KEY"), never a value.
Randomness: use a CSPRNG
Password-reset links, session ids and API keys are only safe if they cannot be guessed. A token built from the current timestamp — md5(now) — has just a handful of likely values, so mallory, who knows roughly when the request was made, can reproduce it in a few tries (Demo 5, vulnerable; CWE-330). Secrets must come from a cryptographically secure random generator (CSPRNG): 32 bytes (256 bits) of randomness, single-use, with a short expiry, is unguessable even to someone who knows the exact time.
How to prevent cryptographic failures
- Classify data; apply controls to everything sensitive, and don't store what you don't need.
- Encrypt in transit: TLS everywhere, HSTS, no mixed content, modern cipher suites.
- Store passwords with bcrypt / scrypt / argon2id — per-user salt and a tuned cost. Never MD5, SHA-1 or plain SHA-256 for passwords.
- Encrypt data at rest with an authenticated mode (AES-GCM, ChaCha20-Poly1305); never ECB; use a fresh nonce per message.
- Keep keys in a KMS / secrets manager, out of source control; rotate them; scan repos and history for leaked secrets.
- Generate all tokens and keys from a CSPRNG; never from timestamps, counters or
rand(). - Prefer vetted libraries and defaults over hand-rolled crypto.
OWASP Top 10:2025 series
This page is part of a ten-page series, one per category:
- A01: Broken Access Control
- A02: Security Misconfiguration
- A03: Software Supply Chain Failures
- A04: Cryptographic Failures (this page)
- A05: Injection
- A06: Insecure Design
- A07: Authentication Failures
- A08: Software or Data Integrity Failures
- A09: Security Logging and Alerting Failures
- A10: Mishandling of Exceptional Conditions
See also How an HTTPS Connection Is Established for the TLS handshake behind the fixed transport, How a Digital Signature Works for hashing and keys, and How Browser Cookies Work and How OAuth 2.0 Works for session tokens.
See Password Hashing: Fast vs Slow Hashes for guesses per second per algorithm.
What the page leaves out
Real hashes and ciphertexts are far longer and the values here are invented for clarity; the page does not compute any actual cryptography. It skips the TLS handshake and certificate checks (see the HTTPS page), key derivation and wrapping, pepper and HMAC, nonce-reuse failures in GCM, timing-safe comparison, certificate and key rotation details, and post-quantum concerns. The five scenarios are independent snapshots, not one running system.