webfilteringdatabase.com
Home Find Your Solution
Features
Domain Categorization API Real-Time Classification 59 Filtering Categories Offline Database (100M) ML Classification Content Classification
Industries
K-12 Schools Corporate Healthcare Government ISPs
Tools
Domain Lookup Bulk Categorization Category Explorer
Resources
Pricing API Documentation Login / Sign Up
How-To Guide

How to Redact Credit Card Numbers

Learn how to automatically detect and redact credit card numbers (PANs) from text, logs, and documents. Ensure PCI-DSS compliance with Luhn-validated detection and secure masking techniques for payment card data.

12 min read
Code examples included
Updated Jan 2025
In This Guide
Section 01

Overview

Credit card numbers, also known as Primary Account Numbers (PANs), are highly sensitive financial data that require stringent protection under PCI-DSS (Payment Card Industry Data Security Standard).

Why it matters: These 13-19 digit numbers can be used to make fraudulent purchases, and their exposure constitutes a significant security incident that can result in substantial fines, legal liability, and reputational damage.

Luhn + BIN Detection

Anonymization API uses Luhn algorithm validation combined with BIN (Bank Identification Number) pattern recognition to detect credit card numbers with 99.9% accuracy.

Every Network, Every Format

Our system identifies cards from all major networks including Visa, Mastercard, American Express, Discover, JCB, and regional networks. We handle various formatting styles including spaces, dashes, and continuous digits.

Logs, Transcripts & Records

Whether you're sanitizing log files, processing customer support transcripts, or anonymizing transaction records, our API ensures that credit card numbers are consistently detected and redacted according to PCI-DSS requirements.

Flexible Masking Formats

We support multiple masking formats to meet different compliance and business needs while ensuring sensitive data is never exposed.

PCI-DSS Compliant Redaction
Before Anonymization
Customer paid with card 4532-0123-4567-8901, CVV 123, exp 12/25
After Anonymization
Customer paid with card [CREDIT_CARD], CVV [CVV], exp [EXPIRY]

Luhn Validation

Only valid card numbers are detected, reducing false positives

All Major Networks

Visa, Mastercard, Amex, Discover, JCB, and more

PCI-DSS Ready

Compliant masking formats for audit requirements

Section 02

PCI-DSS Compliance

The Payment Card Industry Data Security Standard (PCI-DSS) establishes comprehensive requirements for protecting cardholder data. Understanding these requirements is essential for implementing proper credit card redaction strategies.

Critical: PCI-DSS violations can result in fines of $5,000 to $100,000 per month, increased transaction fees, and even loss of the ability to accept card payments. Proper card number redaction is not optional - it's a fundamental security requirement.

PCI-DSS Requirements for Card Data

  • Requirement 3.3: Mask PAN when displayed. Show only the first 6 and/or last 4 digits. Personnel with a legitimate business need may see more than the first 6 and last 4 digits.
  • Requirement 3.4: Render PAN unreadable anywhere it is stored, including logs, databases, and backup media.
  • Requirement 3.5: Document and implement procedures to protect cryptographic keys used for encryption of cardholder data.
  • Requirement 4.1: Use strong cryptography and security protocols when transmitting cardholder data over open, public networks.

What Must Be Protected

PCI-DSS defines cardholder data as:

  • Primary Account Number (PAN): The 13-19 digit card number - the main focus of this guide
  • Cardholder Name: Name as it appears on the card
  • Expiration Date: Card validity date
  • Service Code: 3-digit code on magnetic stripe

Sensitive Authentication Data (SAD)

SAD must NEVER be stored after authorization, even if encrypted:

  • CVV/CVC/CAV2: 3-4 digit security code
  • PIN/PIN Block: Personal Identification Number
  • Full Magnetic Stripe Data: Track 1/Track 2 data

Best Practice: Our API can detect and redact all cardholder data elements in a single pass. Enable comprehensive protection with: entity_types=["CREDIT_CARD", "CVV", "CARD_EXPIRY", "PERSON"]

Acceptable Masking Formats

PCI-DSS allows displaying maximum of first 6 and last 4 digits. Common compliant formats include:

PCI-Compliant Masking Examples
************8901  (Last 4 only - most common)
453201******8901  (First 6 + Last 4)
4532-01**-****-8901  (Preserving format)
XXXX-XXXX-XXXX-8901  (Alternative mask character)
Section 03

Quick Start

Get started with credit card redaction in just a few lines of code. This example demonstrates the simplest way to detect and redact card numbers from text using our API.

from anonymization import Client

client = Client(api_key="your_api_key")

result = client.anonymize(
    text="Payment received: card 4532015112830366",
    entity_types=["CREDIT_CARD"]
)

print(result.anonymized_text)
# Output: Payment received: card [CREDIT_CARD]
const { AnonymizationClient } = require('@anonymization/api');

const client = new AnonymizationClient('your_api_key');

const result = await client.anonymize({
    text: "Payment received: card 4532015112830366",
    entityTypes: ["CREDIT_CARD"]
});

console.log(result.anonymizedText);
// Output: Payment received: card [CREDIT_CARD]
curl -X POST https://api.anonymizationapi.com/v2/anonymize \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Payment received: card 4532015112830366",
    "entity_types": ["CREDIT_CARD"]
  }'

The API response includes details about each detected card number:

{
  "anonymized_text": "Payment received: card [CREDIT_CARD]",
  "entities": [
    {
      "type": "CREDIT_CARD",
      "text": "4532015112830366",
      "start": 23,
      "end": 39,
      "confidence": 0.99,
      "metadata": {
        "card_brand": "VISA",
        "luhn_valid": true,
        "bin": "453201"
      }
    }
  ]
}
Section 04

Card Formats and Brands

Credit card numbers follow specific patterns based on the card network (brand). Our API recognizes all major card networks and their varying formats.

Supported Card Networks

Card Brand Patterns
Visa:           4xxx xxxx xxxx xxxx     (16 digits, starts with 4)
Mastercard:     5[1-5]xx xxxx xxxx xxxx (16 digits, starts with 51-55)
                2[2-7]xx xxxx xxxx xxxx (16 digits, starts with 22-27)
American Express: 3[47]xx xxxxxx xxxxx  (15 digits, starts with 34 or 37)
Discover:       6011 xxxx xxxx xxxx     (16 digits, starts with 6011, 65, 644-649)
JCB:            35xx xxxx xxxx xxxx     (16 digits, starts with 35)
Diners Club:    3[068]xx xxxx xxxx xx   (14 digits)
UnionPay:       62xx xxxx xxxx xxxx     (16-19 digits, starts with 62)

Format Variations

Card numbers appear in various formats across different systems:

Detected Format Variations
4532015112830366        (Continuous)
4532 0151 1283 0366     (Space-separated groups of 4)
4532-0151-1283-0366     (Dash-separated)
4532.0151.1283.0366     (Dot-separated)
3782 822463 10005       (Amex format: 4-6-5 grouping)

Luhn Algorithm Validation

All credit card numbers must pass the Luhn check digit algorithm. Our API validates this to dramatically reduce false positives:

# Luhn validation is enabled by default
result = client.anonymize(
    text="Card: 4532015112830366",  # Valid Luhn
    entity_types=["CREDIT_CARD"]
)
# Detected and redacted

# Invalid card numbers are not detected
result = client.anonymize(
    text="Card: 4532015112830367",  # Invalid Luhn
    entity_types=["CREDIT_CARD"]
)
# NOT detected - Luhn check fails

# Optionally disable Luhn validation for edge cases
result = client.anonymize(
    text=text,
    entity_types=["CREDIT_CARD"],
    options={"card_luhn_validate": False}
)

Test Card Numbers

The API recognizes well-known test card numbers used in development:

# Test cards are detected by default
result = client.anonymize(
    text="Test: 4111111111111111",  # Visa test card
    entity_types=["CREDIT_CARD"]
)

# Optionally skip test cards (not recommended for security)
result = client.anonymize(
    text=text,
    entity_types=["CREDIT_CARD"],
    options={"card_skip_test_numbers": True}
)
Detection at a Glance

Luhn-validated detection across every major card network

99.9% Detection accuracy with Luhn validation
13-19 Digits in a Primary Account Number (PAN)
6 + 4 Max digits displayable under PCI-DSS Req 3.3
$100K Potential monthly fine for PCI-DSS violations
Section 05

Anonymization Techniques

Choose the appropriate credit card anonymization technique based on your PCI compliance requirements and business needs.

1

Full Redaction (Default)

Completely replaces the card number with a placeholder tag. Maximum security, suitable for logs and data exports.

Card: 4532-0151-1283-0366
Card: [CREDIT_CARD]
2

PCI-Compliant Last 4 Masking

Shows only the last 4 digits, the most common PCI-compliant format for receipts and customer-facing displays.

Card: 4532-0151-1283-0366
Card: ****-****-****-0366
3

BIN + Last 4 Masking

Preserves the first 6 (BIN) and last 4 digits. Useful for fraud analysis while maintaining compliance.

Card: 4532-0151-1283-0366
Card: 4532-01**-****-0366
4

Format-Preserving Tokenization

Replaces with a fake but valid-looking card number. Same input always produces same output within a session. Perfect for test data.

Card: 4532-0151-1283-0366
Card: 4916-3385-7412-9603
5

Brand-Preserving Pseudonymization

Generates a fake card number of the same brand. The replacement is Luhn-valid and maintains the same network prefix.

Card: 4532-0151-1283-0366 (Visa)
Card: 4716-8293-0451-7823 (Visa)
# Full redaction (default)
result = client.anonymize(text, entity_types=["CREDIT_CARD"], mode="redact")

# PCI-compliant last 4 masking
result = client.anonymize(text, entity_types=["CREDIT_CARD"], mode="mask",
    options={"card_show_last": 4})

# BIN + Last 4 masking
result = client.anonymize(text, entity_types=["CREDIT_CARD"], mode="mask",
    options={"card_show_first": 6, "card_show_last": 4})

# Format-preserving tokenization
result = client.anonymize(text, entity_types=["CREDIT_CARD"], mode="pseudonymize")

# Brand-preserving pseudonymization
result = client.anonymize(text, entity_types=["CREDIT_CARD"], mode="pseudonymize",
    options={"card_preserve_brand": True})
Section 06

Code Examples

Sanitizing Log Files

Process application logs to remove any accidentally logged card numbers:

log_entries = [
    "2024-01-15 14:32:01 INFO Payment processed: 4532015112830366",
    "2024-01-15 14:32:02 ERROR Card declined: 5425233430109903",
    "2024-01-15 14:32:03 DEBUG Request body: {card: '378282246310005'}"
]

results = client.batch_anonymize(
    items=[{"text": log} for log in log_entries],
    entity_types=["CREDIT_CARD"]
)

for r in results:
    print(r.anonymized_text)
# 2024-01-15 14:32:01 INFO Payment processed: [CREDIT_CARD]
# 2024-01-15 14:32:02 ERROR Card declined: [CREDIT_CARD]
# 2024-01-15 14:32:03 DEBUG Request body: {card: '[CREDIT_CARD]'}

Complete Payment Data Redaction

Redact all payment-related information including CVV and expiration dates:

payment_data = """
Transaction Details:
Card: 4532-0151-1283-0366
Cardholder: John Smith
CVV: 123
Expiry: 12/25
Amount: $150.00
"""

result = client.anonymize(
    text=payment_data,
    entity_types=["CREDIT_CARD", "CVV", "CARD_EXPIRY", "PERSON"]
)

print(result.anonymized_text)
# Transaction Details:
# Card: [CREDIT_CARD]
# Cardholder: [PERSON]
# CVV: [CVV]
# Expiry: [CARD_EXPIRY]
# Amount: $150.00

Real-Time Log Stream Processing

Process logs in real-time to prevent card data from being persisted:

import logging

class PCILogFilter(logging.Filter):
    def __init__(self, api_client):
        super().__init__()
        self.client = api_client

    def filter(self, record):
        # Redact any card numbers before logging
        result = self.client.anonymize(
            text=record.msg,
            entity_types=["CREDIT_CARD", "CVV"]
        )
        record.msg = result.anonymized_text
        return True

# Apply filter to logger
logger = logging.getLogger("payment")
logger.addFilter(PCILogFilter(client))

Card Number Detection Without Redaction

Scan documents for card numbers to identify PCI scope:

def scan_for_card_data(file_path):
    with open(file_path, 'r') as f:
        content = f.read()

    result = client.detect(
        text=content,
        entity_types=["CREDIT_CARD", "CVV"]
    )

    if result.entities:
        print(f"ALERT: Found {len(result.entities)} card data items in {file_path}")
        for entity in result.entities:
            print(f"  - {entity.type} at line {entity.line}, confidence: {entity.confidence}")
            if entity.metadata.get('card_brand'):
                print(f"    Brand: {entity.metadata['card_brand']}")
        return True
    return False
Section 07

Best Practices

1

Always Keep Luhn Validation Enabled

Luhn validation dramatically reduces false positives while ensuring all valid card numbers are caught:

# Default: Luhn validation enabled (recommended)
result = client.anonymize(
    text=text,
    entity_types=["CREDIT_CARD"]
)

# Luhn validation prevents false positives like:
# - Order numbers: 1234567890123456
# - Account IDs: 9876543210987654
# - Random 16-digit numbers
2

Include Related Payment Data

Card numbers alone don't constitute full payment data. Always redact CVV, expiry, and cardholder name together:

# Comprehensive payment data redaction
result = client.anonymize(
    text=payment_text,
    entity_types=[
        "CREDIT_CARD",      # Primary Account Number
        "CVV",              # Security code (MUST never be stored)
        "CARD_EXPIRY",      # Expiration date
        "PERSON"            # Cardholder name
    ]
)
3

Implement at Multiple Layers

Defense in depth: apply card redaction at multiple points in your system:

  • Input validation: Redact before storing any user input
  • Logging: Filter logs before writing to disk
  • Data export: Redact before any data leaves your system
  • Backup: Ensure backups contain only redacted data
  • Analytics: Process data before loading into analytics systems
4

Use Appropriate Masking for Context

Different contexts require different masking levels:

# Customer receipts: Show last 4
receipt_result = client.anonymize(text, entity_types=["CREDIT_CARD"],
    mode="mask", options={"card_show_last": 4})

# Internal logs: Full redaction
log_result = client.anonymize(text, entity_types=["CREDIT_CARD"],
    mode="redact")

# Fraud analysis: BIN + Last 4
fraud_result = client.anonymize(text, entity_types=["CREDIT_CARD"],
    mode="mask", options={"card_show_first": 6, "card_show_last": 4})
5

Audit and Alert on Detection

Set up monitoring to alert when card numbers are found in unexpected places:

PCI Requirement: You must have processes to detect and alert on potential cardholder data exposures. Consider setting up automated scanning of logs, databases, and file systems with alerts when card numbers are detected.

Section 08

Frequently Asked Questions

How accurate is credit card detection?

Our detection achieves 99.9% accuracy with Luhn validation enabled. The combination of pattern matching, Luhn checksum verification, and BIN validation ensures extremely high precision. False positives from random 16-digit numbers are virtually eliminated.

Does the API support tokenization for PCI scope reduction?

Yes, our format-preserving tokenization can help reduce PCI scope by replacing real card numbers with tokens that maintain the same format but cannot be reversed without the tokenization key. However, consult with your QSA about your specific compliance requirements.

How do I handle encrypted card numbers?

The API detects card numbers in plain text. Encrypted card data (which looks like random characters) will not be detected, which is the expected behavior - encrypted data doesn't need additional redaction. If you're storing encrypted cards, ensure the encryption is done before any logging or data export.

Can I detect partial card numbers?

By default, the API looks for complete, valid card numbers. To detect partial numbers (like the last 4 digits in "ending in 1234"), use: options={"card_detect_partial": True}. Note this may increase false positives.

What about card numbers in images or PDFs?

The API processes text input. For images or scanned documents, use OCR first to extract text, then pass to our API. For PDFs with embedded text, extract the text layer first. We can recommend OCR partners if needed.

How do I handle magnetic stripe data?

Track 1 and Track 2 data from magnetic stripes are detected with: entity_types=["CREDIT_CARD", "MAGNETIC_STRIPE"]. This sensitive authentication data (SAD) must never be stored after authorization per PCI-DSS.

Is the API itself PCI compliant?

Our API is designed to help you achieve PCI compliance by redacting card data. We do not store any card numbers that pass through our API. For your own compliance, review our security documentation and consider whether card data transit through our API fits your PCI scope.

Keep Reading

Related Guides

Start Redacting Credit Cards Today

Achieve PCI-DSS compliance with 99.9% accurate card detection and compliant masking options.