BBizKit

redact.creditCard

v0.1.0 latest

Redact a credit card number by masking all digits except the last 4, preserving separators, per PCI DSS Requirement 3.4.

redactcredit-cardpci-dsspiimaskingpayment

Redact a credit card number by masking all digits except the last 4, preserving separators, per PCI DSS Requirement 3.4.

Signature

function creditCard(v: string): string

Problem

Credit card numbers in payment logs, receipts, and error reports must be masked per PCI DSS. Different systems format cards with spaces, dashes, or no separators. Naive masking that strips separators produces inconsistent output that makes format-sensitive downstream consumers fail.

How It Works

Iterates character by character, replacing each digit before the last 4 with '' while preserving non-digit separators (spaces, dashes) in their original positions. Cards with fewer than 5 digits are returned unchanged. Empty input returns '**'.

Boundaries

  • Does not validate Luhn checksum — masking only.
  • Does not detect card brand — all brands receive the same last-4 masking.
  • Returns the input unchanged if it contains fewer than 5 digits.

Replaces

Common boilerplate this function replaces:

v.replace(/\d(?=\d{4,})/g, '*')

Examples

redact.creditCard("4111-1111-1111-1111");  // "****-****-****-1111"
redact.creditCard("378282246310005");  // "***********0005"
redact.creditCard("4111 1111 1111 1111");  // "**** **** **** 1111"
redact.creditCard("");  // "***"
redact.creditCard("1234");  // "1234"

Standards

Caveats

  • Separator preservation is character-level: each non-digit character in the original string appears at its original position in the output.
  • Cards with exactly 4 digits are returned unchanged — there is nothing to mask.

FAQ

How to mask a credit card number in JavaScript for PCI compliance?

redact.creditCard('4111-1111-1111-1111') returns '--****-1111' — masks all digits except last 4 per PCI DSS Requirement 3.4.

How to preserve dashes when masking credit card numbers?

redact.creditCard() preserves all non-digit separators in their original positions. Dashes, spaces, and other separators are retained.

How to redact Amex card numbers differently from Visa?

redact.creditCard() applies uniform last-4 masking regardless of brand. For brand-specific display formatting, use format.creditCard() instead.

What happens when masking a short card number?

Numbers with fewer than 5 digits are returned unchanged. Empty strings return '***'.

How to handle credit card redaction in payment logs?

Pass the raw card string (with or without separators) to redact.creditCard(). Output preserves the original separator pattern with all but the last 4 digits masked.