A CVV test is a check that your checkout sends the card verification value with the authorization request, reads the issuer's answer, and keeps nothing afterward. Under PCI DSS, the CVV (CVV2 for Visa, CVC2 for Mastercard, CID for American Express) is sensitive authentication data. You may transmit it in an authorization request. You may not store it once authorization is complete, encrypted or not. That one rule shapes every test you run.

What a CVV test actually covers

People say "CVV test" and mean five different things. Separate them before you write a test plan, because each one fails in a different way.

  • Format validation. Three digits for Visa, Mastercard, and Discover. Four digits for the American Express CID, and it sits on the front of the card, not the back.
  • Transmission. The value reaches the processor inside the authorization message and nowhere else.
  • Response handling. Your code maps the issuer's verification code to the right business outcome instead of lumping everything into "declined."
  • Non-retention. No database row, no log line, no session variable, no queue payload holds the value after the response comes back.
  • Decline paths. A mismatch declines. An unknown result does not quietly pass as a match.

The PCI DSS requirements that apply

PCI DSS v4.0.1 puts CVV in the sensitive authentication data bucket under Requirement 3.3. Requirement 3.3.1 says SAD is not stored after authorization. The sub-requirements get specific: 3.3.1.1 covers files, servers, and paper; 3.3.1.2 covers authorization logs. Requirement 3.3.2 closes the loophole people reach for first, which is encrypting the CVV and calling it protected. Encryption does not make SAD storable.

The practical effect is that a compliant CVV test can only run in two places: a processor sandbox, or production with a card you own. Any test that puts a real cardholder's CVV into a staging database has already failed the audit, no matter what the test result says.

Response codes worth testing

Visa publishes CVV2 result codes that most processors pass through or map onto. Build a test case for each one, because the failure modes hide in the ambiguous values.

  • M (match): the happy path, and the only one that should authorize on CVV grounds alone.
  • N (no match): should decline or route to step-up review per your fraud policy.
  • P (not processed): the issuer never checked it. Do not treat as a pass.
  • U (unknown, or issuer not participating): common outside the US. Many merchants accept these, which is a business decision, not a compliance one.
  • S (should have been present): the issuer says the card supports CVV2 but your request omitted it.
  • X (no response): a timeout or routing failure, not a verification result.

How to run the test

  1. Pull the sandbox test card numbers from your processor's documentation. Each one maps to a specific CVV outcome.
  2. Submit a matching CVV and confirm the authorization succeeds.
  3. Submit a mismatched CVV and confirm the decline code you expected.
  4. Inspect the request payload in your own logs. The CVV should be absent or masked, and the mask should be applied at capture time, not by a log filter.
  5. Query your database and search your session store, cache, and message queues for the value. Search for the literal digits, not the field name.
  6. Repeat with a card you own in production. One transaction is enough to confirm the live path matches the sandbox path.

That last step matters more than people expect. Sandboxes and production run different configurations often enough that passing tests prove very little on their own.

Mistakes that show up in assessments

  • Caching the CVV in a session so a retry can reuse it. Retries must re-collect the value or resend the original authorization, not replay stored SAD.
  • Full request logging enabled in staging and left on in production. Debug logging is the single most common source of stored SAD.
  • Treating U and P as matches in the fraud rules, then wondering why chargebacks did not move.
  • Testing only the happy path, so the decline handler has never actually run.
  • Assuming a third-party payment page removes your obligation. It reduces scope, but the script requirements under 6.4.3 and the change detection duties under 11.6.1 still apply.

Evidence to keep

Assessors ask for test scripts, sandbox results, and a sample of redacted production logs showing the CVV field absent. Keep the SAQ version you file next to the test records so the scope is unambiguous. A clean CVV test is short to document and hard to fake, which is exactly why it is worth doing properly.