How to Read EMV CVM Lists — Cardholder Verification Method Explained

Every EMV card defines its preferred cardholder verification methods in tag 0x8E — CVM List. This ordered list tells the terminal which verification to try first (offline PIN, online PIN, signature, or none), under what conditions, and what to fall back to if it fails. This guide walks through parsing every byte of the CVM List with real examples from Visa, Mastercard, Amex, and Discover cards.

1. CVM List Structure (Tag 0x8E)

CVM List bytes:
[Amount X (4 bytes)] [Amount Y (4 bytes)] [CVM Entry (2 bytes)]... [CVM Entry]...

Amount X and Y: BCD-encoded amounts (8-digit values) used as thresholds
CVM Entry (2 bytes per method):
  Byte 1: [CVM Code (6 bits)] [CVM Condition (2 bits)]
  Byte 2: [CVM Result — fallback if this method fails]

# Real Visa card CVM List (hex):
# 00 00 00 00 00 00 00 00  — X=0, Y=0 (no amount thresholds)
# 41 03  — CVM Entry 1: Enciphered PIN by ICC, If terminal supports → fallback to Signature
# 1E 03  — CVM Entry 2: Signature, If terminal supports → fallback to Signature (yes, this means "always fallback to sig")
# 1F 00  — CVM Entry 3: No CVM required, Always → no fallback

2. CVM Codes — All Defined Methods

CodeMethodDescription
0x00Fail CVMTransaction cannot proceed (terminal error)
0x02Enciphered PIN verified onlinePIN encrypted by terminal, verified by issuer host
0x03Plaintext PIN verified by ICCPIN sent in plaintext to card for verification
0x04Plaintext PIN verified by ICC + signatureBoth needed (rare)
0x05Enciphered PIN verified by ICCPIN encrypted with card's RSA key (offline enciphered)
0x41Enciphered PIN verification by ICCOffline enciphered PIN (ISO 9564 format 0)
0x42Enciphered PIN verification by ICCOffline enciphered PIN (ISO 9564 format 2)
0x1ESignature (paper)Merchant checks paper receipt signature
0x1FNo CVM requiredNo cardholder verification (low value, transit, contactless)
0x5AConsumer Device CVMOn-device CVM (fingerprint, face) — CDCVM for Apple Pay/Google Pay

3. CVM Conditions

CVM Condition (lower 2 bits of CVM entry byte 1):
00 = Always — apply this method regardless of transaction type
01 = If unattended cash — ATM/kiosk without operator
10 = If not unattended cash — attended terminal, not ATM
11 = If terminal supports the CVM — terminal checks capability flag

4. CVM Result Byte — Fallback Rules

CVM Result (entry byte 2):
Meaning: "If this CVM fails, try this next method"
Same codes as CVM Code table above.
Common patterns:
  0x03 → fallback to plaintext PIN online
  0x1E → fallback to signature
  0x00 → no fallback (transaction fails if this CVM fails)
  0x1F → fallback to no CVM (accept without verification)

5. Real World CVM List Examples

Visa Credit Card (USA, Chip + Signature)

CVM List: 00 00 00 00 00 00 00 00  1E 03 1E 00 1F 00
# X=0, Y=0 (no thresholds)
# Entry 1: Signature, (not unattended) → fallback Signature (= no fallback, same as 0)
# Entry 2: Signature, Always → no fallback
# Entry 3: No CVM, Always → no fallback
# Interpretation: Prefer signature for attended txns, accept signature for all, no CVM for low value

Visa Debit Card (USA, Online PIN Preferred)

CVM List: 00 00 00 01 00 00 00 00  02 03 1E 03 1F 00
# X=0x00000001? No — amounts are 8 digits BCD
# Entry 1: Online enciphered PIN, (not unattended) → fallback Signature
# Entry 2: Signature, (not unattended) → fallback Signature
# Entry 3: No CVM, Always

Mastercard (CDCVM for Contactless)

CVM List: 00 00 00 00 00 00 00 00  5A 03 41 03 1E 03
# Entry 1: Consumer Device CVM (CDCVM), (not unattended) → fallback offline PIN
# Entry 2: Offline enciphered PIN, (not unattended) → fallback Signature
# Entry 3: Signature, (not unattended) → fallback Signature
# First CDCVM (fingerprint/face), then PIN, then signature

6. Setting Up Terminal CVM Processing

def process_cvm(cvm_list, terminal_capabilities, amount):
    """Terminal-side CVM List processing."""
    # Parse amount thresholds X and Y
    x_amount = bcd_to_int(cvm_list[:4])
    y_amount = cvm_list[4:8]  # Y is in application currency?

    entries = cvm_list[8:]  # CVM entries after amounts
    for i in range(0, len(entries), 2):
        code = entries[i] >> 2          # Upper 6 bits
        condition = entries[i] & 0x03   # Lower 2 bits
        fallback_code = entries[i+1]

        # Check if terminal supports this CVM
        if not terminal_supports(code, terminal_capabilities):
            continue

        # Check condition
        if not condition_matches(condition, terminal_type, amount):
            continue

        # Execute CVM
        result = execute_cvm(code)
        if result == 'success':
            return code
        # CVM failed — use fallback
        code = fallback_code  # Next iteration tries fallback
Test this yourself: Our CVM List Decoder parses any CVM List hex dump into a human-readable table showing method names, conditions, and fallback rules. Paste raw EMV tag 0x8E data and get instant decode.

Related Tools

CVM List Decoder — Parse CVM List hex to methods | EMV TLV Parser — Decode full EMV card data | EMV Cryptogram Visualizer — ARQC generation | EMV Tag Reference — Full tag list