CVC verification is a card-not-present fraud control: the three- or four-digit code proves the cardholder has physical access to the card, since CVC is never stored by merchants after authorization and is not present on card magnetic stripes. Disabling CVC verification — whether by removing the CVC field from the checkout form or by configuring Stripe Radar to allow cvc_check != 'pass' — removes this signal entirely. The practical result is that stolen card numbers without physical card access become viable for fraudulent purchases. PCI-DSS 4.0 Req 8.3 covers authentication factors for payment flows; CWE-287 (Improper Authentication) captures the failure mode when a required authentication element is bypassed.
Medium because explicitly disabling CVC verification removes a core card-not-present fraud signal, making the store viable for stolen-card attacks where the attacker lacks physical card access.
CVC verification is on by default for all major providers and requires no code to enable. The action needed is to verify it has not been disabled.
For Stripe Elements, <CardElement /> includes the CVC field automatically — do not configure it out:
// CORRECT — default CardElement includes CVC
<CardElement />
// WRONG — do not remove the CVC field via custom options
<CardElement options={{ disableLink: true, hidePostalCode: true }}
// Even hidePostalCode is fine — but never disable the cvc field itself
/>
In the Stripe Dashboard under Radar rules, check that no rule reads cvc_check != 'pass' in an Allow if condition. If you find one, delete it. For legitimate recurring charges on saved payment methods (where CVC is unavailable by PCI rules), document the exemption and confirm the initial card enrollment collected CVC.
ID: ecommerce-payment-security.fraud-prevention.cvc-verification-enabled
Severity: medium
What to look for: Check whether any payment provider configuration explicitly disables or bypasses CVC/CVV verification. Count all card element configurations and Radar rule references. For Stripe, look for Radar rules that might allow cvc_check != 'pass', or charge configurations with capture_method: 'manual' without CVC validation. Check whether the official SDK components include a CVC field (they do by default — look for any configuration that removes it via hidePostalCode or similar options). Also search for any comment or configuration indicating CVC is intentionally skipped.
Pass criteria: CVC/CVV verification is enabled (which is the default). No more than 0 configurations should disable it. If using Stripe Elements, the CVC field is included in the card element (default behavior). For recurring charges on saved payment methods where CVC is unavailable, this is an acceptable skip.
Fail criteria: CVC verification is explicitly disabled in provider configuration, or CVC field is removed from the checkout form, or Radar rules allow CVC failures to proceed without challenge.
Skip (N/A) when: The project exclusively processes recurring charges on previously saved payment methods where CVC is unavailable by design (PCI rules prohibit storing CVC). In this case, note that initial card-save should have used CVC.
Detail on fail: Describe the disabled verification. Example: "Stripe configuration includes a Radar rule allowing transactions where cvc_check == 'fail' to proceed — CVC failures are not declining transactions"
Remediation: CVC verification is on by default for all major providers and requires no special configuration to enable. If you've disabled it, re-enable it:
// Stripe: do NOT add rules that bypass CVC failures
// In Stripe Radar, avoid rules like:
// Allow if cvc_check != 'pass'
// For Elements, do not remove the CVC field — include it by default:
// <CardElement /> includes number, expiry, and CVC automatically
// For PaymentElement, CVC is included and cannot be removed — this is correct
If you have a legitimate reason to not collect CVC (e.g., one-click checkout with saved cards), document it and ensure the initial card save collected CVC at the time.