A CVV test checklist is the set of checks you run against a payment form to confirm the security code is collected, validated, sent to the processor, and then discarded. It covers field behavior, server-side rules, sandbox test numbers, and what your logs and database are allowed to keep. This is the list I work through before a checkout page goes live.
Start with the input field
Most CVV bugs are input bugs. Open the form on a phone and on a desktop and check the basics.
- Length is 3 digits for Visa, Mastercard, and Discover, and 4 for American Express. The limit should change when the card brand is detected.
- Only digits are accepted. Letters, spaces, and punctuation get rejected or stripped before submit.
- The keyboard opens in numeric mode, usually through inputmode numeric, so mobile users are not hunting for a number row.
- The field is labeled clearly as the security code, with a hint about where to find it. "CVV" alone confuses people.
- Paste works. Blocking paste breaks password managers and annoys everyone.
- Autocomplete is set to cc-csc so browsers and wallet apps fill it correctly.
Validate on the client and again on the server
Client-side checks are for user experience. The server is where the real rules live, because anyone can skip your JavaScript. Confirm the server rejects an empty CVV, rejects non-numeric input, rejects wrong lengths per brand, and never trusts a brand flag sent from the browser without checking the card number itself. A request with a missing CVV should fail cleanly with a field-level error, not a 500.
Use sandbox test numbers, never live cards
Every processor ships test card numbers for this exact job. With Stripe, for example, 4242 4242 4242 4242 approves with any future expiry and any CVC in test mode. The card 4000 0000 0000 0127 returns an incorrect CVC decline, and 4000 0000 0000 0002 returns a generic decline. Run each one and watch what the customer sees. Then try a valid card number with an empty CVV, a two-digit CVV, and a five-digit CVV to see how the form reacts before the request ever reaches the processor.
Check what happens to the CVV after authorization
This is the part that gets teams in trouble. PCI DSS forbids storing the CVV, the full magnetic stripe data, and the PIN block after authorization, even if the data is encrypted. So verify the following by actually looking.
- The CVV is not written to your database, in any column, encrypted or not.
- It does not appear in application logs, request dumps, or error trackers like Sentry.
- It is not sent to analytics, session replay tools, or marketing pixels.
- Support dashboards and admin panels mask it or never receive it.
- Your payment token, not the card data, is what your systems store for repeat charges.
A quick test: place a sandbox order, then grep your logs and database dumps for the three-digit code you typed. If it shows up, stop and fix it before launch.
Test the failure paths
Happy paths are easy. The declines are where UX and security collide. Check that an incorrect CVV shows a clear, non-accusatory message, that the customer can correct it without re-entering the whole card, and that your system does not reveal whether the card number or the security code was the problem beyond what the issuer returns. If you use 3D Secure, confirm the step-up flow still works when the CVV check fails first. And confirm a failed attempt does not lock the account or clear the cart.
The short version
Field rules, brand-aware lengths, server-side validation, sandbox test cards, decline handling, and zero retention of the code after authorization. Run those six checks and you have covered the things that actually break in production.