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
| Code | Method | Description |
|---|---|---|
| 0x00 | Fail CVM | Transaction cannot proceed (terminal error) |
| 0x02 | Enciphered PIN verified online | PIN encrypted by terminal, verified by issuer host |
| 0x03 | Plaintext PIN verified by ICC | PIN sent in plaintext to card for verification |
| 0x04 | Plaintext PIN verified by ICC + signature | Both needed (rare) |
| 0x05 | Enciphered PIN verified by ICC | PIN encrypted with card's RSA key (offline enciphered) |
| 0x41 | Enciphered PIN verification by ICC | Offline enciphered PIN (ISO 9564 format 0) |
| 0x42 | Enciphered PIN verification by ICC | Offline enciphered PIN (ISO 9564 format 2) |
| 0x1E | Signature (paper) | Merchant checks paper receipt signature |
| 0x1F | No CVM required | No cardholder verification (low value, transit, contactless) |
| 0x5A | Consumer Device CVM | On-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