Why this matters for PCI DSS
PCI DSS 4.0 repeatedly mandates "strong cryptography":
- 4.2.1 — strong cryptography for transmission of CHD over open networks.
- 3.5.1 — strong cryptography for storage of PAN.
- 8.3.2 — strong cryptography for authentication factors during transmission and storage.
The PCI SSC's "Cryptographic Algorithms and Key Sizes" annex defines "strong" by reference to NIST SP 800-131A, which deprecates everything in our list.
Math.random() for tokens is the single most common cause of session-prediction and password-reset-token-prediction CVEs in JavaScript apps.
How to fix it
Hashing — replace MD5 / SHA-1 with SHA-256 (or SHA-3 for new designs).
Password hashing — never use a fast hash (SHA-256 included). Use one of: argon2id (preferred for new code), bcrypt, or scrypt. PHP's password_hash($pw, PASSWORD_ARGON2ID), .NET's PasswordHasher<T>, Node's argon2 npm package.
Symmetric encryption — replace DES / 3DES / RC4 with AES-256-GCM (preferred) or ChaCha20-Poly1305. Both are AEAD, so they handle integrity and confidentiality together.
Random tokens (browser) — replace Math.random() with crypto.getRandomValues():
// BAD
const token = Math.random().toString(36).slice(2);
// GOOD
const buf = new Uint8Array(32);
crypto.getRandomValues(buf);
const token = Array.from(buf, b => b.toString(16).padStart(2, '0')).join('');
// Or for a UUID:
const uuid = crypto.randomUUID();
Random tokens (Node.js) — require('crypto').randomBytes(32).toString('hex').
Random tokens (PHP) — bin2hex(random_bytes(32)).
Random tokens (.NET) — RandomNumberGenerator.GetBytes(32).
Random tokens (Python) — secrets.token_hex(32) from the standard library.
Audit dependencies — many old npm packages (CryptoJS, jsSHA in MD5/SHA1 mode) appear in transitive deps. npm audit won't catch this; manual grep does.