← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Web Crypto API

javascript ES2015 Advanced
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list eslint and semgrep as the tools. Misuse of Math.random() for crypto or use of third-party JS crypto libraries instead of Web Crypto can be caught by semgrep rules or ESLint security plugins, but these are not default linter rules — they require specialist configuration. Not d3 because the pattern isn't caught by a default linter setup, and not d7 because automated tooling (semgrep) can reliably surface the common patterns.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix indicates replacing Math.random() with crypto.getRandomValues() or swapping a third-party library for crypto.subtle calls. This is typically a targeted replacement within one component or module — not a one-liner (requires understanding the API and adapting call sites), but not a cross-cutting refactor either. Hardcoded IV or AES-CBC without MAC mistakes may require a few co-located changes, keeping this at e3.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to context is web only, and the choice of how to implement client-side crypto is generally localised to a crypto utility module or specific feature (e.g. e2e encryption). It doesn't impose a codebase-wide tax — most application code is unaffected. However, if non-extractable keys and IndexedDB are used, it does impose some ongoing complexity in that component, so b3 is appropriate rather than b1.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception is explicit: developers believe Math.random() and crypto.getRandomValues() are equivalent for security purposes. This directly contradicts how randomness is conceptually understood — 'random is random' — when in fact Math.random() is deterministic and predictable. Additional traps include assuming AES-CBC is safe without a MAC, and reusing IVs. These are well-documented gotchas that contradict intuition from general programming contexts, placing this at t7.

About DEBT scoring →

Also Known As

crypto.subtle SubtleCrypto Web Crypto browser crypto CSPRNG browser

TL;DR

Browser-native cryptographic operations — crypto.subtle provides AES-GCM encryption, ECDSA signing, PBKDF2 key derivation, and SHA digests without external libraries.

Explanation

Web Crypto API (crypto.subtle): digests (SHA-256/384/512), key generation (AES-GCM, RSA-OAEP, ECDSA), encryption/decryption (AES-GCM), signing/verification (RSA-PSS, ECDSA), key derivation (PBKDF2, HKDF), key import/export. All operations are async (Promise-based) and work with ArrayBuffer. crypto.getRandomValues() provides cryptographically secure random bytes synchronously. CryptoKey objects are non-extractable by default — prevents key material from leaking to JavaScript variables.

Common Misconception

Math.random() and crypto.random() are equivalent for security — Math.random() is not cryptographically secure and is predictable; always use crypto.getRandomValues() for any security-sensitive random data.

Why It Matters

End-to-end encrypted browser applications require browser-native cryptography — Web Crypto provides standardised, hardware-accelerated operations with non-extractable keys, removing the need for untrusted third-party crypto libraries.

Common Mistakes

  • Math.random() for tokens, IDs, or any security-sensitive randomness
  • Storing private keys in localStorage — use non-extractable CryptoKey with IndexedDB
  • Not using authenticated encryption (AES-GCM) — AES-CBC without MAC allows ciphertext tampering
  • Hardcoded IVs — always generate a unique random IV per encryption operation

Code Examples

✗ Vulnerable
// Math.random for crypto — predictable and insecure:
const token = Math.random().toString(36).substring(2);
// Token can be predicted with knowledge of the PRNG state
✓ Fixed
// Cryptographically secure random token:
const bytes = crypto.getRandomValues(new Uint8Array(32));
const token = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');

// AES-GCM authenticated encryption:
async function encrypt(plaintext, key) {
    const iv      = crypto.getRandomValues(new Uint8Array(12)); // Unique per message
    const encoded = new TextEncoder().encode(plaintext);
    const ciphertext = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv },
        key,        // CryptoKey — non-extractable
        encoded
    );
    return { iv, ciphertext }; // Store IV alongside ciphertext
}

Added 16 Mar 2026
Edited 22 Mar 2026
Views 36
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Google 8 Amazonbot 6 ChatGPT 6 Perplexity 4 Unknown AI 3 Ahrefs 2 Majestic 1
crawler 29 crawler_json 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Use the Web Crypto API (crypto.subtle) for client-side cryptography — it's native, hardware-accelerated, and avoids shipping a JS crypto library; use for hashing, signing, and key derivation in the browser
📦 Applies To
javascript ES2015 web
🔗 Prerequisites
🔍 Detection Hints
Third-party JS crypto library (CryptoJS, forge) when Web Crypto API would suffice; Math.random() for cryptographic purposes in browser
Auto-detectable: ✓ Yes eslint semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update
CWE-327 CWE-338

✓ schema.org compliant