Back to scan results
Check 19 of 24

Weak Cryptography References

We grep your homepage HTML and same-origin JavaScript for references to algorithms that PCI DSS classifies as broken or unsuitable: MD5, SHA-1, DES, RC4, and the predictable Math.random() as a source of "randomness" for security tokens.

What this check probes

  • MD5 — explicit references like md5(, CryptoJS.MD5, require('md5'). MD5 is broken for collision resistance (since 2004) and unfit for any security purpose; still acceptable as a non-security checksum.
  • SHA-1 — explicit references. Broken collision resistance since SHAttered (2017). Acceptable for HMAC-SHA-1 in legacy-compat scenarios but not for new code.
  • DES / 3DES — references to DES, TripleDES, DESede. Sweet32 (CVE-2016-2183) made even 3DES unsuitable for > few hundred MB of data on a single key.
  • RC4 — references to RC4. Banned by RFC 7465 (2015) due to multiple practical attacks.
  • Math.random() near token-related identifiers (token, session, uuid, nonce, id). Math.random() is a deterministic pseudo-random generator suitable for animations and games, never for security; the seed is recoverable from a few outputs.
  • Custom crypto signs — xor(, naive base64-as-encryption, str_rot13, common amateur patterns.

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.

Fixed it? Re-run the scan to confirm.

Run scan again