Unencrypted financial data at rest — account numbers, SSNs, card tokens, transaction history — is a direct path from database breach to identity theft and fraud. CWE-311 (missing encryption) and CWE-326 (inadequate key length) are both in play when a project stores plaintext or uses AES-128: attackers who exfiltrate the database file get immediately usable cardholder data. NIST SP 800-111 and PCI-DSS 4.0 Req-3.5 require AES-256 or stronger because shorter keys are vulnerable to brute-force as compute costs fall. A single exposed plaintext column is enough to trigger breach notification obligations and PCI fines.
Critical because a single unencrypted sensitive column converts a database read vulnerability into direct cardholder data exposure with no further attacker effort required.
Switch to AES-256-GCM for all sensitive fields in src/lib/encryption.ts or src/utils/crypto.ts. Prefer authenticated encryption (GCM mode) over CBC to also detect tampering. Use the Node.js built-in crypto module — do not add a third-party wrapper for this:
import crypto from 'node:crypto';
const ALGO = 'aes-256-gcm';
export function encryptField(plaintext: string, key: Buffer): string {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv(ALGO, key, iv);
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
return [iv.toString('hex'), tag.toString('hex'), encrypted.toString('hex')].join(':');
}
For database-level coverage, enable TDE on your provider (AWS RDS, Supabase) — that covers all columns, including ones you haven't explicitly wrapped. Both approaches together satisfy NIST SC-28 and PCI-DSS 4.0 Req-3.5.
finserv-encryption.data-at-rest.aes256-encryptioncriticalaes-256-gcm, aes-256-cbc). Check for transparent database encryption (TDE) or application-level encryption. A key size under 256 bits does not count as pass — do not pass if any sensitive field uses weaker than AES-256."3 of 5 sensitive columns unencrypted — account_number, ssn, and card_token stored plaintext in customer_data table".finserv-encryption.data-at-rest.tde-or-column-encryption for database-level encryption details, and finserv-encryption.key-management.nist-algorithm-justification for algorithm selection.src/lib/encryption.ts or src/utils/crypto.ts). For Node.js, use the crypto module. Choose one of two approaches:
import crypto from 'crypto';
const cipher = crypto.createCipher('aes-256-cbc', encryptionKey);
let encrypted = cipher.update(accountNumber, 'utf8', 'hex');
encrypted += cipher.final('hex');
await db.insert({ account_number: encrypted });