Plaintext Password Storage
Plaintext password storage keeps credentials recoverable, so one database breach exposes every user and fuels credential stuffing elsewhere. Store passwords only as slow, salted Argon2id/bcrypt hashes, and prefer passwordless or multi-factor authentication.
Plaintext password storage means the system keeps user passwords in a form an attacker can recover: literal text, reversible encryption, or a fast unsalted hash like raw MD5/SHA-1. Because users reuse passwords across services, a single breach of such a store endangers accounts far beyond the breached system.
Why It Happens
Plaintext is the simplest thing that works for login: compare the submitted string to the stored string. "Email me my password" features require recoverable storage, so teams choose reversible schemes. Some developers reach for a familiar hash (MD5, SHA-256) believing any hash is enough, not realizing that fast, unsalted hashing falls quickly to GPU-accelerated cracking and precomputed rainbow tables.
Why It Hurts
Databases get breached — through SQL injection, leaked backups, insider access, or misconfigured cloud storage. When passwords are plaintext or reversibly stored, the breach immediately yields working credentials for every user. Even fast hashes are cracked en masse: commodity hardware tests billions of guesses per second against unsalted SHA-256. Stolen credentials feed credential-stuffing attacks against other sites, multiplying the damage. The exposure also typically violates GDPR, PCI-DSS, and similar regimes, bringing fines and breach-notification obligations.
Warning Signs
- Passwords are visible as readable values in the database or logs.
- The product can email a user their existing password.
- Stored hashes are unsalted, or use MD5/SHA-1/SHA-256 directly.
- The same plaintext password produces the same hash for every user (no per-user salt).
Better Alternatives
Store only a slow, salted, one-way hash using a purpose-built password KDF: Argon2id (preferred), scrypt, or bcrypt. These are deliberately expensive and memory-hard, making large-scale cracking impractical. Apply a unique per-user salt automatically (these algorithms do this) so identical passwords hash differently and rainbow tables are useless. Optionally add a server-side secret (pepper) stored separately from the database. Better still, reduce reliance on passwords altogether with passwordless or multi-factor authentication, passkeys, or federated identity.
How to Refactor Out of It
- Stop the bleeding: never log passwords, and disable any feature that emails them.
- Adopt a password KDF (Argon2id) for all new and changed passwords.
- Migrate existing hashes transparently: on next successful login, rehash the verified password with the new algorithm; for plaintext stores, this also lets you discard the original.
- Force a reset for accounts that do not log in within a grace period.
- Remove any column or backup that contains recoverable passwords, and rotate database credentials if a breach is suspected.
- Add tests asserting that stored values are never reversible to the input.