September 29, 2022
AUTHORS
with the contribution of
Related articles
AUTHORS
with the contribution of

How to Store CVV Codes and Other Transient Data

If you process card-based payments, you know that not every transaction is approved on the first try, and that it helps to cache CVV numbers so you can retry transactions when needed. But PCI DSS forbids storing CVVs. Skyflow’s transient field tokens provide a way to hold CVVs and other types of sensitive data for immediate use, while ensuring that it’s not retained.

A card verification code or value (CVV - sometimes referred to as CVC, CAV2, CVC2, CVV2, or CID) is a three or four digit number printed on a payment card. The card verification code is typically used for authorization in card-not-present transactions. It’s an additional line of defense in e-commerce transactions against fraud, beyond the card number and expiration date.

However, unlike card numbers and expiration dates, retaining card verification codes is prohibited under PCI DSS Requirement 3.2. Even storing this data securely using cryptographic techniques isn’t allowed under this requirement – all CVVs must be completely removed from the backend system.

But what if you need to retry authorization after initial payment authorization attempts fail? You could prompt a customer for their CVV again, but that could frustrate your customers because it adds friction to your payment flow. 

While persistent storage of CVVs is strictly prohibited, you can temporarily keep a CVV available during authorization. In this article we show you how to use a new feature from Skyflow called transient field tokenization to temporarily keep the CVV available in “volatile storage” long enough to complete authorization and create a seamless customer experience. 

Why Is Handling CVVs So Confusing?

Legal wording and computer code are not always exactly equivalent. Legal wording can be interpreted in a variety of ways, with varying levels of strictness. In this case PCI DSS Requirement 3.2 reads as follows:

“Do not store the card verification code or value (three-digit or four-digit number printed on the front or back of a payment card used to verify card-not-present transactions) after authorization.” 

The key words here are “after authorization”. Let’s take a look at what the PCI Council has to say when explaining the matter, in detail:

“PCI DSS does not prohibit the collection of card verification codes/values prior to authorization of a specific purchase or transaction.”

So before the authorization it’s okay to “collect” CVV values.

“However, it is not permitted to retain card verification codes/values once the specific purchase or transaction for which it was collected has been authorized.”

But once the transaction has been authorized it is not acceptable to keep CVV values.

“All card verification codes/values must be completely removed from the entity’s systems in order to comply with Requirement 3.2.”

At that point – after authorization is complete – the CVV values must not exist anywhere in your system. So this means:

  • A CVV Can’t Be Stored in Logs. Per PCI DSS: “The requirement to not store sensitive authentication data cannot be met by the use of cryptographic techniques.”
  • A CVV Can’t Be Encrypted and Stored in Any of Your Systems, Even If You Use Crypto-Shredding. You can’t encrypt and store CVVs and then destroy encryption keys with crypto-shredding, because the data is still stored, even if it’s theoretically unrecoverable. Per PCI DSS: “Any service or process that claims to “remove” card verification codes/values from storage, yet is able to retrieve them for future authorization, would need to be assessed (e.g. by a QSA or ISA), to confirm that all card verification codes/values have been truly removed from the entity’s systems and are not being stored in any way, shape or form.”

So, unless you can magically retrieve a CVV from the ether without storing it, it’s not okay to be able to retrieve it after the specified transaction is authorized.

To us, this section reads like a lawyer is covering their technical bases. It reiterates the point that you cannot have the CVV after authorization has completed. If any CVV values exist in any of your systems after authorization, you are out of compliance. The concept is fairly clear, but the hard part is interpreting and translating this into system logic.

What Does This Mean in Practice?

To “collect” CVVs for card-not-present transactions you must create a system which absolutely ensures the CVV will not remain in your systems – in encrypted form, in system backups, in system logs, etc. – after the authorization completes. So in translating the legal requirements above into system design requirements, we get the following:

  • After Authorization, Immediately Attempt Deletion
  • Ensure CVV Deletion, Even in a Disaster
  • Control the CVV Security Perimeter

Let’s take a closer look at each of these requirements:

After Authorization, Immediately Attempt Deletion

When payment authorization completes, you must immediately attempt to delete the CVV value from your system. To adhere to the standard as closely as possible, a time-based trigger or a periodic cleanup job is not sufficient. It’s not enough to ensure that a CVV is deleted after an hour or more – much less on a nightly or weekly basis – except as a backup measure for disaster recovery (see next section). 

As soon as the authorization completes, your systems should take immediate action to delete these protected values. But as any technologist knows, any operation, even a straightforward data deletion, can fail. And PCI DSS makes it clear that it’s not sufficient to attempt to delete the CVV – that’s just the first step. You need a backup plan which tolerates deletion failure and ensures deletion in a variety of disaster or service outage scenarios.

Ensure CVV Deletion, Even in a Disaster

PCI DSS requires that you ensure that CVVs aren’t kept in your systems in the event that the initial deletion attempt fails, as might occur in a network outage, a service outage, or another disaster scenario. If your deletion fails, if your application falls over, if your application servers restart, if your rate limits are exceeded… None of these are excuses for failing to delete CVVs. No matter what happens, you need to be sure that CVVs won’t stay in your systems.

This generally means that you cannot store CVVs on disk. If your approach to handling CVVs could persist these values in the event of a system failure, that puts you out of compliance. This requirement makes memory the natural choice for temporary and PCI-compliant handling of CVVs: if something happens and the system shuts down, the values must be cleared.

You even need a backup plan for partial failure scenarios. For example, if your attempt to delete a CVV fails, but the servers don’t shut down and memory is not cleared. Now what? You need a time-based trigger which will automatically clear any values left after a reasonable “safety period” for transaction authorization. Your system must have fallback safety controls so it’s fault-tolerant and fails gracefully.

Control the CVV Security Perimeter

You need to make absolutely sure that CVVs are not persisted anywhere else. This means that you need to exclude these values from all system logs and backups (client side and server side). And, you need to ensure that it’s not possible for other systems or actors to retrieve these values. If you don’t know who can access these CVVs, and you don’t know who has already accessed the value, then you don’t know if they are being stored elsewhere – and you’re out of compliance.

So, controlling the CVV security perimeter means that you must implement access control to ensure that only the payment application can access the values. This usually means implementing access control using methods like an Access Control List (ACL), Role-Based Access Control (RBAC), and Attribute-Based Access Control (ABAC). Whichever method you choose, you must prevent any other application, user, process, or actor from accessing these values.

You must also implement access audit logging to record access events so that you know if, when, and who accessed which values, so that you can validate that your CVV security perimeter is working. You must both control access and log access – trust and verify.

And as mentioned above, CVVs can’t be backed up or logged. CVVs must remain isolated while held to ensure transaction processing, and never copied or replicated while they’re held during this time. Copying CVVs to backups or logs means you lose control over access and persistence, so you fall out of compliance.

So, is there a way to make meeting these requirements easier?

How Does Skyflow Solve CVV Handling Headaches?

Skyflow Data Privacy Vault is a relational vault, which is much more powerful than a simple token map. A relational vault has tables, columns, rows, and cells – just like a relational database. With Skyflow, you can tokenize any field in any format to support different data use cases.

A transient field is a special type of field where the data is ephemeral and is configured with a time-to-live (TTL) setting. It’s never stored to disk or logged. Each transient field produces a secure transient field token, which is also tied to the field’s TTL setting. After the field expires, the token stops working and the data is deleted everywhere.

You can use a transient field to temporarily hold a CVV so that you can retry authorization in the event of a failed authorization attempt. After you’re done using the CVV for authorization, you should proactively delete or nullify the CVV value, as described above in After Authorization, Immediately Attempt Deletion. But, by using the CVV field’s TTL setting, you can ensure CVV deletion, even in an outage, system failure, or disaster.

With transient field tokenization, your infrastructure is never exposed to the CVV or any other card details. Instead you are given tokens that can be saved to your application storage and referenced in the immediate future to complete card transactions. This ensures you stay PCI compliant, while supporting a frictionless and flexible payment experience.

Let’s see how to set this up using Skyflow.

Creating a Vault for Card Authorization and Transactions

Companies that process credit card transactions can use Skyflow Data Privacy Vault to securely store their customer credit card information in compliance with PCI. Using Skyflow lets companies avoid PCI vendor lock-in, which happens when credit card data is stored within a payment processor like Stripe.

Adding Skyflow vault to your architecture, as shown below, gives you a payment processing system that has the same ease of PCI compliance offered by storing PCI data with a payment processor. But unlike storing PCI data with a single payment processor, this architecture gives you control and ownership over your PCI data, so you have the flexibility to easily work with multiple card processing providers.

Data Architecture Using Skyflow Vault to Avoid PCI Vendor Lock-in

To achieve this, you create a Skyflow vault with a predefined schema for storing credit card information. This typically includes the card holder name, card number, and the expiration date, as shown below.

Skyflow’s Basic Credit Card Vault Schema

Each column is automatically configured to tokenize data to support common payment processing use cases. 

For example, in the image below, the card_number column is set to create a format-preserving deterministic token, meaning the token will still look like a credit card number to ensure interoperability, but it’s random and not mathematically connected to the actual card number. The token is deterministic, meaning that the same card number will produce the same token.

In contrast, the cardholder_name produces a deterministic UUID that doesn’t preserve the format of the original data. Other tokenization schemes are supported, and you can configure them based on the types of operations you need to support. 

Tokenization Settings for Card Number and Cardholder Name in Skyflow Studio

To support temporarily holding CVVs for authorization retry requests, you need to add one more field to the schema: a CVV field configured as a Transient Field, utilizing a Transient UUID Token as shown below. 

This token is a UUID rather than a format preserving token because CVVs are only three or four digits, so from a security perspective the search space would be way too small if the format were preserved. 

Additionally, this token is not deterministic; instead, it’s random. Deterministic tokenization always provides the same token for the same value, which is great for analytical operations like joins and matches across records, columns, and tables. However, CVV values are inherently non-unique and should not be used for matching or joining datasets.

The default time to live setting for CVVs is one hour. Ideally, you want to make this as short as possible based on your average authorization time, which could be just a few minutes. Using a Transient Field gives you the flexibility to adjust this setting based on your requirements and use case.

Transient Field Settings for CVVs in Skyflow Studio

With the vault schema configured, the next step is to collect and tokenize the card data.

CVV Collection and Tokenization

To securely collect PCI data and route it to Skyflow without exposing your frontend or backend infrastructure to this data you must use Skyflow Elements. This feature provides pre-built form elements to collect sensitive data client-side. These elements are hosted by Skyflow and interjected into the client web page as iFrames. Isolating card data this way reduces PCI compliance scope because you avoid exposing your application infrastructure to any sensitive data.

As a simple example, the HTML below sets up a form to collect credit card information, including CVVs.

<div>
  <div id="collectCardNumber" class="empty-div"></div>
  <div id="collectCvv" class="empty-div"></div>
  <div id="collectExpiryMonth" class="empty-div"></div>
  <div id="collectExpiryYear" class="empty-div"></div>
  <div id="collectCardholderName" class="empty-div"></div>
  <div>
    <button id="collectPCIData">Collect PCI Data</button>
  </div>
</div>


You’ll need to mount a Skyflow Element to each of the DIVs to dynamically insert the secure collection fields. The example code below initializes the Skyflow client-side SDK and a collection object, and then mounts a CVV collection element, inserting the secure form field and mapping it to the credit_cards table and cvv column defined by the vault schema.

const skyflowClient = Skyflow.init({
  vaultID: 'my-skyflow-id',
  vaultURL: 'https://my-workspace.vault.skyflowapis.com',
  getBearerToken: generateBearerToken,
});

const collectContainer = skyflowClient.container(Skyflow.ContainerType.COLLECT);

const cvvElement = collectContainer.create({
  table: "credit_cards",
  column: "cvv",
  ...collectStylesOptions,
  label: "CVV",
  placeholder: "cvv",
  type: Skyflow.ElementType.CVV,
});


When the user clicks the collectPCIData button, the form data is stored securely within the vault and tokens are then returned to the frontend. These tokens can then be safely sent to your backend to be stored within your application database, as shown below:

const collectButton = document.getElementById("collectPCIData");
collectButton.addEventListener("click", () => {
  const collectResponse = collectContainer.collect();
  collectResponse.then((response) => {
    // Tokens returned by your Skyflow vault.
    const fieldsTokenData = response.records[0].fields;
    // Save the tokens to your backend system.
    const res = await fetch('/saveCardData', {
      body: JSON.stringify(fieldsTokenData),
      headers: {
        'Content-Type': 'application/json'
      },
      method: 'POST'
    });
  });
});

Card Authorization

At this point, you have tokens stored within your application database that can serve as pointers to the cardholder name, credit card number, expiration month and year, and CVV. With the transient field properties set for CVV, you have given yourself up to one hour to authorize the card, even in the event of a failed authorization attempt.

To authorize a card with tokenized data, instead of calling your payment gateway provider directly, you’ll call a Skyflow Connections API endpoint, passing the tokens in the request, as shown in the code below that uses the Skyflow Node.js SDK

const response = client.invokeConnection({
  connectionURL: 'https://my-workspace.vault.skyflowapis.com/v1/gateway/outboundRoutes/rd5caaf9ee2542deb1e5914923029bc2/v1/authorize,
  methodName: Skyflow.RequestMethod.POST,
  requestHeader: {
    'Content-Type': 'application/json',
    'Authorization': 'Basic 5A6B7C…'
  },
  requestBody: {
    expiry_month: 'e907c7e6-1cbb-48f6-91f8-a6f70e25417a',
    expiry_year: 'e406db9a-f9a6-4468-a8b8-77c05f8c173d',
    card_number: '2232145789539434',
    cvv: '0cb1ccde-1dbc-43d4-9284-a88c046ead45',
    amount: '10000'
  }
});

The tokens will be detokenized securely within the trusted vault environment and then sent to your payment gateway on your behalf. 

The response from the gateway is then returned to your backend with any sensitive data automatically being captured and then tokenized to further isolate your system from exposure to PCI data.

After you’ve received a successful authorization request, you should delete or nullify the CVV value to ensure a strong PCI compliance posture. The CVV field’s TTL setting is a great fallback, but a privacy-conscious company must also proactively remove the CVV when it’s no longer needed.

How Does This Fit into the PCI DSS Framework?

By insulating your frontend and backend infrastructure from PCI data, Skyflow radically simplifies the process of becoming PCI compliant. With Skyflow, you can become PCI compliant in days, rather than weeks or months. In fact, Skyflow customers have implemented secure payment processing solutions using PCI DSS Level 2 self assessment, within one week

And, using Skyflow to store and manage your PCI data doesn’t come at the expense of third-party integrations because you can send card data to trusted, PCI compliant third parties using Skyflow Connections. For example, one Skyflow customer is using the transient fields to store CVVs until authorization is complete and, if needed, switch authorization to an alternate payment processor to complete the transaction. This offers an improved experience for customers who don’t need to re-enter their CVV, all while handling CVVs in full compliance with PCI requirements. Using Skyflow means that you don’t need to choose between having payment processor flexibility and providing a smooth transaction experience to your customers.

Other Uses For Transient Field Tokenization

In this article, we focused primarily on the use case of temporarily holding CVVs for authorization. However, transient field tokenization has many other potential use cases, a few of which are discussed below. It’s a powerful general-purpose data minimization tool that can be a part of nearly any data protection strategy.

Customer Support Queue Management

There have been a number of high-profile data breaches that reveal what happens when data governance and data minimization techniques are inadequate, like the 2021 breach at Robinhood. In such breaches, malicious actors acquired the credentials of a customer support agent (CSA) through social engineering or hacking, and it’s revealed that the agent had access to an entire database of customer records – access well beyond what a CSA would need to do their job. But, this can be prevented: Using a combination of a transient field to track customer support assignments along with a row-based access restriction configured using Skyflow’s governance engine, lets you easily create a customer support system that limits access to only records within a given agent’s assigned queue.

As assignments occur within the customer support system, the customer record’s transient field gets updated with the assigned CSA’s identifier. You can create a policy that limits access to only the rows with a given agent’s identifier. This way, even if a customer support agent’s credentials get compromised, the number of customer records exposed is significantly reduced. Additionally, access will automatically expire based on the configuration of the transient field properties. 

Self-destructing Highly Sensitive Data

Transient fields make it simple to create self-destructing data fields for highly sensitive information. For example, instead of your tax software always needing to store your Social Security Number, if they used Skyflow and a transient field, they could keep it ephemeral for the period in which you need to submit your taxes to the IRS. This significantly reduces the potential for breaches or leaks and reduces compliance scope.

Other forms of highly sensitive data that shouldn’t be permanently stored are PIN numbers and one-time passwords. You can use transient fields to guarantee that this type of data doesn’t end up sticking around longer than intended.

Try Skyflow

Using transient fields and transient field tokenization help to reduce credit card authorization friction while keeping your systems PCI compliant. These capabilities also enable other complex use cases where you might want data to be available, but not permanently stored (even in the event of disaster). A transient field is easy to set up and gives you flexibility over how long sensitive data elements are held, and you can customize the schema and tokenization support for your specific use case.

To learn more, please contact us for a demo or try Skyflow.

You Might Also Be Interested In:

No items found.