One of the most important, if not unsettling, principles in security is that there is no such thing as absolute security. It's possible to bypass any and all security measures given enough time and resources. Look no further than the Snowden revelations. This exposed the degree to which a variety of technologies previously thought to be secure had, in fact, already been compromised. The best that any organization can do is to increase the cost of hacking to where the expense doesn't justify the reward. And, to be as aware as possible to when breaches occur.

As an organization that deals with securing payment information, this reality affects how we design our systems. It also impacts the tools our merchant customers use. The broad guidelines set forth in PCI DSS ultimately govern us. The latest of which added the following requirement to the most common assessment questionnaire:

The entirety of all payment pages delivered to the consumer's browser originates directly from a third-party PCI DSS validated service provider(s).

This wrinkle may seem innocuous at first, but it has important implications. I'd like to show how the online payment form you may be using, even if from a respected payment gateway, potentially invalidates your ability to use PCI v3 SAQ A assessment and exposes you to undue risk.

Attack Vector

Specifying that sensitive payment forms originate directly from the gateway/third-party service prevents a compromise of the online merchant's servers from accessing users' payment information directly. For instance, if serves a payment form that is hacked, the hacker can place an unobtrusive javascript agent on the payment page that provides direct access to the user's card information.

Only by rendering the sensitive fields of the payment form in an iFrame, themselves delivered directly from the payment gateway or processor servers, will a compromised merchant payment page not have access to the user's credit card information. The browser's security model prevents access to the DOM of an iFrame from the host page, eliminating that particular vector.

Any online payment form that renders within the DOM of a merchant controlled page, even if it's a javascript library served from the gateway's servers, violates the spirit of PCI DSS requirement and should only be implemented after an understanding of the increased risks.

The self-hosted or transparent redirect payment form is one of the forms most susceptible to this type of attack.

Self-hosted Online Payment Forms

Many companies offer a self-hosted solution to help online merchants collect card information. Prior to PCI DSS v3, using this approach allowed you to use the SAQ A, the simplest form of self-assessment. The basic implementation is to add a payment form to your web page including input fields for the card number and CVV.

The form submits directly to the payment gateway server which redirects back to the merchant site with a generated token. The server stores only the token, which is completely safe. This sounds like a good thing, right?


I created a repo of hacked payment pages which contains a self hosted payment form page, `index.html`, and a page that uses the Spreedly redirect, `spreedly-redirect.html`. Every page in this repo contains a script tag which pulls in a malicious script: a basic Cross-Site Scripting (XSS) attack which mimics what an attacker can do should the merchant servers be compromised.

This repo contains a little server that serves a malicious script, `malicious.js` and accepts POSTs of siphoned off form data.  The script is very basic. It adds a keydown listener to inputs on the infected page. When pressing a key, a function runs which goes through every input, grabs form values and sends them off to the malicious server. This script could be much more elegant, but this works for demonstration purposes. The main point of this demonstration is that the script does not care about the semantics of the online payment form. If the form is in the DOM it can be siphoned.

When I submit the form to my server using either the self-hosted form or the transparent redirect form, no PCI sensitive data reaches my server. Unfortunately, the malicious script was able to successfully send all the information to the hacker's server. Here is the log on the hacker's server. A compromise of the number and cvv is clear.

Malicious server received data:{"first_name":"Miki", "last_name":"Rezentes", "card_number":"4111111111111111", "cvv":"123", "month":"01", "year":"2025"}

This illustrates that payment forms rendered within the host page DOM are vulnerable to silent attacks. There is no log evidence of stripped data from the payment form being sent off to ne'er do wells. As long as the malicious script shares the same DOM as the payment form, the sensitive data is being breached. No one has any idea it is happening. It could go on for years. Even if the script is found, there is little way to figure out how long the attack has been going on or the extent of the damage. The lack of visibility into the attack is frightening from a security perspective. If there is no way to detect an attack, you are basically living on a wing and a prayer. Not a great strategy for keeping your customer's data safe.

Let's look at how an iFrame-based payment form, while still vulnerable to a host page compromise, offers additional assurances.

iFrame Payment Forms

If you're an online merchant hoping to rely on the simple SAQ A questionnaire to achieve PCI compliance, you can't rely on solutions that just render a payment form within your host page, even if it's a javascript library that renders the fields inline (for the reasons described above - if the fields are in the host page DOM, they are vulnerable). To qualify for the SAQ A while still controlling the payment form UX you must use:

an inline frame (iFrame) to a PCI DSS compliant third-party processor facilitating the payment process

Unlike self-hosted solutions, using an iFrame based solution thwarts scripts on the host page from accessing sensitive data within the iFrames. When the server doesn't share the two pages, the browser security model prevents the host page from accessing the iFrame DOM.

By way of example, the hacked-form repo also contains a page that utilizes Spreedly's iFrame solution, `iframe.html`. When I enter my information into the payment form using Spreedly's iFrame it protects the input fields from scripts on the parent page. Here is the hacker's log after submitting customer information via iFrame:

Malicious server received data:{"payment_method_token":"PmmqnOe5ccyM9i5xTyQZqdtvk8q", "first_name":"Miki", "last_name":"Rezentes", "month":"12", "year":"2017"}

Siphoning the sensitive card data inside the iFrame fields is not possible. Instead, only the values exposed to the host page are captured.

iFrame Vulnerabilities

It may appear that using an iFrame solution provides absolute security. But wait - didn't we learn earlier that there's no such thing as absolute security? In fact, there is a way to siphon cardholder data when using iFrame payment forms from compromised merchant servers.

Upon hacking the merchant's host page, the attacker could replace our iFrame form with their own using javascript that removes and adds elements to the DOM. The user wouldn't know any better since the compromised form and the secure version are visually identical. As the user enters their card information into the compromised form, the attacker can siphon the information back to their servers. If they stopped here, however, the payment page wouldn't be fully functional (since no transaction takes place).

To cover their tracks, the attacker would also send a real request for payment method tokenization to the payment gateway. This tactic would preserve the expected workflow and delay discovery. From the card holder's perspective, everything is normal, they are simply entering their card data. Everything is normal from the online merchant's perspective since the result is a proper payment method token. From the gateway's perspective, everything is normal as well. They are making and returning tokens. It appears all is well. In fact, a hacker is sitting quietly on the compromised payment page, replacing the real payment form with a version that silently siphons sensitive data.

So does this mean that iFrame based solutions are just as flawed as same-DOM approaches like transparent redirects? Not quite

iFrame Abuse Protections

There is no way to prevent all attacks. However, with an iFrame solution we can increase the likelihood of discovery and detection. This, in turn, changes the risk/reward calculation for the attacker.

First, if the payment gateway knows a merchant is using an iFrame payment form to submit payment methods, they can turn off other methods of submitting payment methods. This effectively prevents an attacker from using alternate payment APIs to mimic a legitimate flow in parallel to siphoning off the data. At Spreedly, we provide the following option to our customers:

The attacker is forced to use the same endpoint as the iFrame payment form (due to the restrictions implemented above). The gateway can now utilize the Access-Control-Allow-Origin HTTP header to prevent any POSTs to the iFrame endpoint that originates from another origin (this header is checked in a pre-flight request by all browsers before sending a cross-domain POST). This forces all requests to the iFrame endpoint to come from the iFrame itself - not a potentially compromised merchant page.

Finally, now that we've prevented the attacker from executing a valid payment method request from the users' browser, their only remaining option is to send the card data to a server environment of their own control. Here they can spoof the iFrame request by explicitly setting the required HTTP headers. These requests will succeed, but they are now traceable back to infrastructure controlled by the attacker, increasing their risk. Additionally, these requests will come from a relatively few source IPs. This makes their traffic pattern more easily identifiable assuming proper visibility and alerting from the payment gateway.

There is always a way for a compromised merchant page to expose card data. Using an iFrame, however, is the only way to reliably detect the intrusion and shift the burden of security to the gateway.


When it comes to PCI DSS, one principle is clear: access to sensitive data increases your responsibility for security. Any non-iFrame payment forms allow access to the sensitive data and therefore disqualify online merchants from using the SAQ-A. Be very diligent when using tools from your payment provider. Verify and insist upon iFrame-based payment forms.