BitBootcampBitBootcamp ← all explainers 🔄 Review ⚙ Settings

CYBER-02-003-P · Primer — A02 Cryptographic Failures

The idea in one sentence

A02 Cryptographic Failures is what happens when sensitive data — passwords, cards, health records, tokens — is exposed because the cryptography meant to protect it is weak, misused, or simply absent.

Why it exists

This category sits at number two on the OWASP Top 10 2021, and its name is the story. In earlier lists it was called "Sensitive Data Exposure" — a name that describes the symptom (data got out) rather than the cause. OWASP renamed it to point at the root: the exposure is a failure in cryptography, not bad luck. It exists as its own category because the failure is so common and so quiet. Crypto feels like a solved problem, so teams pull in a library, get something encrypting, watch the tests go green, and move on. The default that shipped fast is rarely the default that stays safe — and nothing breaks visibly when it is wrong. The data is still there, the app still works, and the gap only surfaces the day someone reads a disk, sniffs a network, or dumps a database.

Think of it like leaving your house keys on the kitchen table because you "always lock the door"— you trust the lock (TLS) but ignore the fact that anyone walking in can grab the keys (the encryption key) and open every door later. The lock works, but the overall security collapses the moment the keys are exposed.

How it works

There are three ways the protection fails, and they map to where the data lives. Absent — the data is written with no cipher at all: cleartext in a database column, a log line, or an unencrypted backup (CWE-311, missing encryption). Anyone who reads the storage reads the secret. In transit — a login page served over plain HTTP, or an internal service that skips TLS "because it's inside the network." On any shared path the traffic is readable, and "inside" is not a trust boundary. Weak — an algorithm that was fine a decade ago is broken now: MD5 or SHA-1 for integrity, DES for encryption, an unsalted fast hash for passwords (CWE-327, a broken or risky algorithm). The math has moved on; the code hasn't.

Worked example: A web app stores user passwords as SHA‑256(password) with no salt. An attacker dumps the users table containing [email protected] → 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd.... Using a pre‑computed rainbow table of common passwords hashed with SHA‑256, the attacker matches the hash to the password "password" in under a minute. If the app had used bcrypt with a cost factor of 12 and a unique salt per password, the same attack would require billions of hash operations per guess, making it infeasible.

See it — data protected, or exposed, at the two decision points

flowchart TD
  D["Sensitive data<br/>passwords, cards"] --> Q{"Crypto applied?"}
  Q -->|"absent or weak"| X["Plaintext on disk<br/>or readable wire"]
  X --> B["Attacker reads<br/>the secret"]
  Q -->|"strong, at rest<br/>and in transit"| E["Ciphertext"]
  E --> K{"Key protected?"}
  K -->|"hard-coded in code"| B
  K -->|"in a vault, rotated"| S["Data stays safe"]

The one gotcha

The failure is almost never the cipher — it is key management. Teams burn hours debating which algorithm is "most secure" and then hard‑code the key in source, check it into Git, or ship it inside the mobile app where anyone can extract it (CWE‑321). Modern AES and TLS are sound; nobody is breaking AES‑256. What breaks is a key that everyone can read, a key that never rotates, a key sitting next to the ciphertext it protects. Encryption with an exposed key is decoration. The second half of the same gotcha: encrypted in transit is not encrypted at rest. TLS protects the wire; the moment the data lands in the database it is only as safe as the disk‑level protection you also configured. People check the padlock, see HTTPS, and assume the whole path is covered — it isn't. You need protection at both ends and a key the attacker can't reach.

The one-line takeaway

Protect the data and guard the key — the cipher is rarely the problem.

Where you'll meet it

You meet A02 the moment you store a password or send a request. Web frameworks already solve the hard part if you let them: Django, Rails, and Spring Security ship slow, salted password hashing (PBKDF2, bcrypt, scrypt, or Argon2) as the default — don't replace it with a "fast" hash. TLS is enforced with HSTS and a redirect; there is no reason to serve secrets over HTTP in 2021 or since. For keys, use a managed KMS or secret vault (AWS KMS, GCP KMS, HashiCorp Vault) so the key never lives in code and rotation is a config change — and keep secrets out of instance metadata (IMDS) and environment dumps. Dependency scanners like Snyk and Dependabot flag libraries with known‑broken crypto, and a testing proxy like Burp Suite will show you cleartext fields and missing‑TLS endpoints during a review. Every one of these tools reports the finding as CWE‑311 (missing encryption) or CWE‑327 (a broken algorithm) — the same two IDs behind A02.

Named concepts: cryptographic failures, encryption at rest, encryption in transit, key management