
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Sat, 04 Apr 2026 10:56:24 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Automatically replacing polyfill.io links with Cloudflare’s mirror for a safer Internet]]></title>
            <link>https://blog.cloudflare.com/automatically-replacing-polyfill-io-links-with-cloudflares-mirror-for-a-safer-internet/</link>
            <pubDate>Wed, 26 Jun 2024 20:23:41 GMT</pubDate>
            <description><![CDATA[ polyfill.io, a popular JavaScript library service, can no longer be trusted and should be removed from websites ]]></description>
            <content:encoded><![CDATA[ <p></p><p>polyfill.io, a popular JavaScript library service, can no longer be trusted and should be removed from websites.</p><p><a href="https://sansec.io/research/polyfill-supply-chain-attack">Multiple reports</a>, corroborated with data seen by our own client-side security system, <a href="https://developers.cloudflare.com/page-shield/">Page Shield</a>, have shown that the polyfill service was being used, and could be used again, to inject malicious JavaScript code into users’ browsers. This is a real threat to the Internet at large given the popularity of this library.</p><p>We have, over the last 24 hours, released an automatic JavaScript URL rewriting service that will rewrite any link to polyfill.io found in a website proxied by Cloudflare <a href="https://cdnjs.cloudflare.com/polyfill/">to a link to our mirror under cdnjs</a>. This will avoid breaking site functionality while mitigating the risk of a supply chain attack.</p><p>Any website on the free plan has this feature automatically activated now. Websites on any paid plan can turn on this feature with a single click.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5R0ht5q4fAwm8gm3a2Xe5U/6b3ec28498e76ff75e37b58f3673e49a/image1-22.png" />
            
            </figure><p>You can find this new feature under <a href="https://dash.cloudflare.com/?to=/:account/:zone/security/settings">Security ⇒ Settings</a> on any zone using Cloudflare.</p><p>Contrary to what is stated on the polyfill.io website, Cloudflare has never recommended the polyfill.io service or authorized their use of Cloudflare’s name on their website. We have asked them to remove the false statement, and they have, so far, ignored our requests. This is yet another warning sign that they cannot be trusted.</p><p>If you are not using Cloudflare today, we still highly recommend that you remove any use of polyfill.io and/or find an alternative solution. And, while the automatic replacement function will handle most cases, the best practice is to remove polyfill.io from your projects and replace it with a secure alternative mirror like Cloudflare’s even if you are a customer.</p><p>You can do this by searching your code repositories for instances of polyfill.io and replacing it with <a href="https://cdnjs.cloudflare.com/polyfill/">cdnjs.cloudflare.com/polyfill/</a> (Cloudflare’s mirror). This is a non-breaking change as the two URLs will serve the same polyfill content. All website owners, regardless of the website using Cloudflare, should do this now.</p>
    <div>
      <h2>How we came to this decision</h2>
      <a href="#how-we-came-to-this-decision">
        
      </a>
    </div>
    <p>Back in February, the domain polyfill.io, which hosts a popular JavaScript library, was sold to a new owner: Funnull, a relatively unknown company. <a href="/polyfill-io-now-available-on-cdnjs-reduce-your-supply-chain-risk">At the time, we were concerned</a> that this created a supply chain risk. This led us to spin up our own mirror of the polyfill.io code hosted under cdnjs, a JavaScript library repository sponsored by Cloudflare.</p><p>The new owner was unknown in the industry and did not have a track record of trust to administer a project such as polyfill.io. The concern, <a href="https://x.com/triblondon/status/1761852117579427975">highlighted even by the original author</a>, was that if they were to abuse polyfill.io by injecting additional code to the library, it could cause far-reaching security problems on the Internet affecting several hundreds of thousands websites. Or it could be used to perform a targeted supply-chain attack against specific websites.</p><p>Unfortunately, that worry came true on June 25, 2024, as the polyfill.io service was being used to inject nefarious code that, under certain circumstances, redirected users to other websites.</p><p>We have taken the exceptional step of using our ability to modify HTML on the fly to replace references to the polyfill.io CDN in our customers’ websites with links to our own, safe, mirror created back in February.</p><p>In the meantime, additional threat feed providers have also taken the decision to <a href="https://github.com/uBlockOrigin/uAssets/commit/91dfc54aed0f0aa514c1a481c3e63ea16da94c03">flag the domain as malicious</a>. We have not outright blocked the domain through any of the mechanisms we have because we are concerned it could cause widespread web outages given how broadly polyfill.io is used with some estimates indicating <a href="https://w3techs.com/technologies/details/js-polyfillio">usage on nearly 4% of all websites</a>.</p>
    <div>
      <h3>Corroborating data with Page Shield</h3>
      <a href="#corroborating-data-with-page-shield">
        
      </a>
    </div>
    <p>The original report indicates that malicious code was injected that, under certain circumstances, would redirect users to betting sites. It was doing this by loading additional JavaScript that would perform the redirect, under a set of additional domains which can be considered Indicators of Compromise (IoCs):</p>
            <pre><code>https://www.googie-anaiytics.com/analytics.js
https://www.googie-anaiytics.com/html/checkcachehw.js
https://www.googie-anaiytics.com/gtags.js
https://www.googie-anaiytics.com/keywords/vn-keyword.json
https://www.googie-anaiytics.com/webs-1.0.1.js
https://www.googie-anaiytics.com/analytics.js
https://www.googie-anaiytics.com/webs-1.0.2.js
https://www.googie-anaiytics.com/ga.js
https://www.googie-anaiytics.com/web-1.0.1.js
https://www.googie-anaiytics.com/web.js
https://www.googie-anaiytics.com/collect.js
https://kuurza.com/redirect?from=bitget</code></pre>
            <p>(note the intentional misspelling of Google Analytics)</p><p>Page Shield, our client side security solution, is available on all paid plans. When turned on, it collects information about JavaScript files loaded by end user browsers accessing your website.</p><p>By looking at the database of detected JavaScript files, we immediately found matches with the IoCs provided above starting as far back as 2024-06-08 15:23:51 (first seen timestamp on Page Shield detected JavaScript file). This was a clear indication that malicious activity was active and associated with polyfill.io.</p>
    <div>
      <h3>Replacing insecure JavaScript links to polyfill.io</h3>
      <a href="#replacing-insecure-javascript-links-to-polyfill-io">
        
      </a>
    </div>
    <p>To achieve performant HTML rewriting, we need to make blazing-fast HTML alterations as responses stream through Cloudflare’s network. This has been made possible by leveraging <a href="/rust-nginx-module">ROFL (Response Overseer for FL)</a>. ROFL powers various Cloudflare products that need to alter HTML as it streams, such as <a href="https://developers.cloudflare.com/speed/optimization/content/fonts/">Cloudflare Fonts,</a> <a href="https://developers.cloudflare.com/waf/tools/scrape-shield/email-address-obfuscation/">Email Obfuscation</a> and <a href="https://developers.cloudflare.com/speed/optimization/content/rocket-loader/">Rocket Loader</a></p><p>ROFL is developed entirely in Rust. The memory-safety features of Rust are indispensable for ensuring protection against memory leaks while processing a staggering volume of requests, measuring in the millions per second. Rust's compiled nature allows us to finely optimize our code for specific hardware configurations, delivering performance gains compared to interpreted languages.</p><p>The performance of ROFL allows us to rewrite HTML on-the-fly and modify the polyfill.io links quickly, safely, and efficiently. This speed helps us reduce any additional latency added by processing the HTML file.</p><p>If the feature is turned on, for any HTTP response with an HTML Content-Type, we parse all JavaScript script tag source attributes. If any are found linking to polyfill.io, we rewrite the src attribute to link to our mirror instead. We map to the correct version of the polyfill service while the query string is left untouched.</p><p>The logic will not activate if a Content Security Policy (CSP) header is found in the response. This ensures we don’t replace the link while breaking the CSP policy and therefore potentially breaking the website.</p>
    <div>
      <h3>Default on for free customers, optional for everyone else</h3>
      <a href="#default-on-for-free-customers-optional-for-everyone-else">
        
      </a>
    </div>
    <p>Cloudflare proxies millions of websites, and a large portion of these sites are on our free plan. Free plan customers tend to have simpler applications while not having the resources to update and react quickly to security concerns. We therefore decided to turn on the feature by default for sites on our free plan, as the likelihood of causing issues is reduced while also helping keep safe a very large portion of applications using polyfill.io.</p><p>Paid plan customers, on the other hand, have more complex applications and react quicker to security notices. We are confident that most paid customers using polyfill.io and Cloudflare will appreciate the ability to virtually patch the issue with a single click, while controlling when to do so.</p><p>All customers can turn off the feature at any time.</p><p>This isn’t the first time we’ve decided a security problem was so widespread and serious that we’d enable protection for all customers regardless of whether they were a paying customer or not. Back in 2014, we enabled <a href="/shellshock-protection-enabled-for-all-customers">Shellshock protection</a> for everyone. In 2021, when the log4j vulnerability was disclosed <a href="/cve-2021-44228-log4j-rce-0-day-mitigation/">we rolled out protection</a> for all customers.</p>
    <div>
      <h2>Do not use polyfill.io</h2>
      <a href="#do-not-use-polyfill-io">
        
      </a>
    </div>
    <p>If you are using Cloudflare, you can remove polyfill.io with a single click on the Cloudflare dashboard by heading over to <a href="https://dash.cloudflare.com/?to=/:account/:zone/security/settings">your zone ⇒ Security ⇒ Settings</a>. If you are a free customer, the rewrite is automatically active. This feature, we hope, will help you quickly patch the issue.</p><p>Nonetheless, you should ultimately search your code repositories for instances of polyfill.io and replace them with an alternative provider, such as Cloudflare’s secure mirror under cdnjs (<a href="https://cdnjs.cloudflare.com/polyfill/">https://cdnjs.cloudflare.com/polyfill/</a>). Website owners who are not using Cloudflare should also perform these steps.</p><p>The underlying bundle links you should use are:</p><p>For minified: <a href="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js">https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js</a>
For unminified: <a href="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.js">https://cdnjs.cloudflare.com/polyfill/v3/polyfill.js</a></p><p>Doing this ensures your website is no longer relying on polyfill.io.</p> ]]></content:encoded>
            <category><![CDATA[CDNJS]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Vulnerabilities]]></category>
            <category><![CDATA[Application Security]]></category>
            <category><![CDATA[Application Services]]></category>
            <category><![CDATA[Supply Chain Attacks]]></category>
            <category><![CDATA[Attacks]]></category>
            <category><![CDATA[Better Internet]]></category>
            <guid isPermaLink="false">3NHy1gOkql57RbBcdjWs5g</guid>
            <dc:creator>Matthew Prince</dc:creator>
            <dc:creator>John Graham-Cumming</dc:creator>
            <dc:creator>Michael Tremante</dc:creator>
        </item>
        <item>
            <title><![CDATA[polyfill.io now available on cdnjs: reduce your supply chain risk]]></title>
            <link>https://blog.cloudflare.com/polyfill-io-now-available-on-cdnjs-reduce-your-supply-chain-risk/</link>
            <pubDate>Thu, 29 Feb 2024 17:51:32 GMT</pubDate>
            <description><![CDATA[ Polyfill.io is now available on cdnjs to reduce the risk of supply chain attacks. Replace your polyfill.io links today for a seamless experience ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4nxvskYVuRnRJHoLUMRY4l/e26d2d6b57eb9a286238ab84863dc947/image1-17.png" />
            
            </figure><p>Polyfill.io is a popular JavaScript library that nullifies differences across old browser versions. These differences often take up substantial development time.</p><p>It does this by adding support for modern functions (via <a href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill">polyfilling</a>), ultimately letting developers work against a uniform environment simplifying development. The tool is historically loaded by linking to the endpoint provided under the domain polyfill.io.</p><p>In the interest of providing developers with additional options to use polyfill, today we are launching an <a href="https://cdnjs.cloudflare.com/polyfill">alternative endpoint under cdnjs</a>. You can replace links to polyfill.io “as is” with our new endpoint. You will then rely on the same service and reputation that <a href="https://cdnjs.com/">cdnjs</a> has built over the years for your polyfill needs.</p><p>Our interest in creating an alternative endpoint was also sparked by some <a href="https://github.com/polyfillpolyfill/polyfill-service/issues/2834">concerns raised by the community</a>, and <a href="https://twitter.com/triblondon/status/1761852117579427975">main contributors</a>, following the transition of the domain polyfill.io to a new provider (Funnull).</p><p>The concerns are that any website embedding a link to the original polyfill.io domain, will now be relying on Funnull to maintain and secure the underlying project to avoid the risk of a supply chain attack. Such an attack would occur if the underlying third party is compromised or alters the code being served to end users in nefarious ways, causing, by consequence, all websites using the tool to be compromised.</p><p>Supply chain attacks, in the context of web applications, are a growing concern for security teams, and also led us to build a client side security product to detect and mitigate these attack vectors: <a href="https://developers.cloudflare.com/page-shield/">Page Shield</a>.</p><p>Irrespective of the scenario described above, this is a timely reminder of the complexities and risks tied to modern web applications. As maintainers and contributors of <a href="https://cdnjs.com/">cdnjs</a>, currently used by <a href="https://w3techs.com/technologies/overview/content_delivery">more than 12% of all sites</a>, this reinforces our commitment to help keep the Internet safe.</p>
    <div>
      <h3>polyfill.io on cdnjs</h3>
      <a href="#polyfill-io-on-cdnjs">
        
      </a>
    </div>
    <p>The full polyfill.io implementation has been deployed at the following URL:</p><p><a href="https://cdnjs.cloudflare.com/polyfill/"><code>https://cdnjs.cloudflare.com/polyfill/</code></a></p><p>The underlying bundle link is:</p><p>For minified: <a href="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js">https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js</a>For unminified: <a href="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.js">https://cdnjs.cloudflare.com/polyfill/v3/polyfill.js</a></p><p>Usage and deployment is intended to be identical to the original polyfill.io site. As a developer, you should be able to simply “replace” the old link with the new cdnjs-hosted link without observing any side effects, besides a possible improvement in performance and reliability.</p><p>If you don’t have access to the underlying website code, but your website is behind Cloudflare, replacing the links is even easier, as you can deploy a Cloudflare Worker to update the links for you:</p>
            <pre><code>export interface Env {}

export default {
    async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise&lt;Response&gt; {
        ctx.passThroughOnException();

        const response = await fetch(request);

        if ((response.headers.get('content-type') || '').includes('text/html')) {
            const rewriter = new HTMLRewriter()
                .on('link', {
                    element(element) {
                        const rel = element.getAttribute('rel');
                        if (rel === 'preconnect') {
                            const href = new URL(element.getAttribute('href') || '', request.url);

                            if (href.hostname === 'polyfill.io') {
                                href.hostname = 'cdnjs.cloudflare.com';
                                element.setAttribute('href', href.toString());
                            }
                        }
                    },
                })

                .on('script', {
                    element(element) {
                        if (element.hasAttribute('src')) {
                            const src = new URL(element.getAttribute('src') || '', request.url);
                            if (src.hostname === 'polyfill.io') {
                                src.hostname = 'cdnjs.cloudflare.com';
                                src.pathname = '/polyfill' + src.pathname;

                                element.setAttribute('src', src.toString());
                            }
                        }
                    },
                });

            return rewriter.transform(response);
        } else {
            return response;
        }
    },
};</code></pre>
            <p>Instructions on how to deploy a worker can be found on our <a href="https://developers.cloudflare.com/workers/get-started/">developer documentation</a>.</p><p>You can also test the Worker on your website without deploying the worker. You can find instructions on how to do this in <a href="/workers-and-webpagetest/">another blog post we wrote in the past</a>.</p>
    <div>
      <h3>Implemented with Rust on Cloudflare Workers</h3>
      <a href="#implemented-with-rust-on-cloudflare-workers">
        
      </a>
    </div>
    <p>We were happy to discover that polyfill.io is a <a href="https://github.com/polyfillpolyfill/polyfill-service">Rust project</a>. As you might know, Rust has been a <a href="/workers-rust-sdk">first class citizen on Cloudflare Workers</a> from the start.</p><p>The polyfill.io service was hosted on Fastly and used their Rust library. We forked the project to add the compatibility for Cloudflare Workers, and plan to make the fork publicly accessible in the near future.</p>
    <div>
      <h3>Worker</h3>
      <a href="#worker">
        
      </a>
    </div>
    <p>The <code>https://cdnjs.cloudflare.com/polyfill/[...].js</code> endpoints are also implemented in a Cloudflare Worker that wraps our Polyfill.io fork. The wrapper uses <a href="https://github.com/cloudflare/workers-rs">Cloudflare’s Rust API</a> and looks like the following:</p>
            <pre><code>#[event(fetch)]
async fn main(req: Request, env: Env, ctx: Context) -&gt; Result&lt;Response&gt; {
    let metrics = {...};

    let polyfill_store = get_d1(&amp;req, &amp;env)?;
    let polyfill_env = Arc::new(service::Env { polyfill_store, metrics });
    
    // Run the polyfill.io entrypoint
    let res = service::handle_request(req2, polyfill_env).await;

    let status_code = if let Ok(res) = &amp;res {
        res.status_code()
    } else {
        500
    };
    metrics
        .requests
        .with_label_values(&amp;[&amp;status_code.to_string()])
        .inc();

    ctx.wait_until(async move {
        if let Err(err) = metrics.report_metrics().await {
            console_error!("failed to report metrics: {err}");
        }
    });

    res
}</code></pre>
            <p>The wrapper only sets up our internal <a href="https://developers.cloudflare.com/workers/observability/metrics-and-analytics/">metrics</a> and <a href="https://developers.cloudflare.com/workers/observability/logging/logpush/">logging</a> tools, so we can monitor uptime and performance of the underlying logic while calling the Polyfill.io entrypoint.</p>
    <div>
      <h3>Storage for the Polyfill files</h3>
      <a href="#storage-for-the-polyfill-files">
        
      </a>
    </div>
    <p>All the polyfill files are stored in a key-value store powered by <a href="https://developers.cloudflare.com/d1/">Cloudflare D1</a>. This allows us to fetch as many polyfill files as we need with a single SQL query, as opposed to the original implementation doing one KV get() per file.</p><p>For performance, we have one Cloudflare D1 instance per region and the SQL queries are routed to the nearest database.</p>
    <div>
      <h3>cdnjs for your JavaScript libraries</h3>
      <a href="#cdnjs-for-your-javascript-libraries">
        
      </a>
    </div>
    <p>cdnjs is hosting over 6k JavaScript libraries as of today. We are looking for ways to improve the service and provide new content. We listen to community feedback and welcome suggestions on our <a href="https://community.cloudflare.com/">community forum</a>, or <a href="https://github.com/cdnjs">cdnjs on GitHub</a>.</p><p><a href="https://developers.cloudflare.com/page-shield/">Page Shield</a> is also available to all paid plans. Log in to turn it on with a single click to increase visibility and security for your third party assets.</p> ]]></content:encoded>
            <category><![CDATA[CDNJS]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Supply Chain Attacks]]></category>
            <guid isPermaLink="false">64KHlCJKCdI1JNa3sCAqpL</guid>
            <dc:creator>Sven Sauleau</dc:creator>
            <dc:creator>Michael Tremante</dc:creator>
        </item>
        <item>
            <title><![CDATA[Coalescing Connections to Improve Network Privacy and Performance]]></title>
            <link>https://blog.cloudflare.com/connection-coalescing-experiments/</link>
            <pubDate>Wed, 13 Oct 2021 12:59:25 GMT</pubDate>
            <description><![CDATA[ Real world experiments for evaluating connection coalescing effects. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Web pages typically have <a href="https://discuss.httparchive.org/t/whats-the-distribution-of-requests-per-page/21/10?u=patmeenan">a large number</a> of embedded subresources (e.g., JavaScript, CSS, image files, ads, beacons) that are fetched by a browser on page loads. Requests for these subresources can prompt browsers to perform further DNS lookups, TCP connections, and TLS handshakes, which can have a significant impact on how long it takes for the user to see the content and interact with the page. Further, each additional request exposes metadata (such as plaintext DNS queries, or unencrypted SNI in TLS handshake) which can have potential privacy implications for the user. With these factors in mind, we carried out a measurement study to understand how we can leverage <a href="https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/">Connection Coalescing</a> (aka <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-9.1.1">Connection Reuse</a>) to address such concerns, and study its feasibility.</p>
    <div>
      <h3>Background</h3>
      <a href="#background">
        
      </a>
    </div>
    <p>The <a href="/http-3-from-root-to-tip/">web has come a long way</a> and initially consisted of very simple protocols. One of them was HTTP/1.0, which required browsers to make a separate connection for every subresource on the page. This design was quickly recognized as having significant performance bottlenecks and was extended with HTTP pipelining and persistent connections in <a href="https://datatracker.ietf.org/doc/html/rfc2616">HTTP/1.1 revision</a>, which allowed HTTP requests to reuse the same TCP connection. But, yet again, this was no silver bullet: while multiple requests could share the same connection, they still had to be serialized one after the other, so a client and server could only execute a single request/response exchange at any given time for each connection. As time passed, websites became more complex in structure and dynamic in nature, and HTTP/1.1 was identified as a major bottleneck. The only way to gain concurrency at the network layer was to use multiple TCP connections to the same origin in parallel, but this meant losing most benefits of persistent connections and ended up overloading the origin servers which were unable to meet the concurrency demand.</p><p>To address these performance limitations, the SPDY protocol was introduced over a decade later. SPDY supported stream multiplexing, where requests to and responses from the server used a single interleaved TCP connection, and allowed browsers to prioritize requests for critical subresources first — that were blocking page rendering. A modified variant of SPDY was standardized by the IETF as HTTP/2 in 2012 and published as <a href="https://datatracker.ietf.org/doc/html/rfc7540">RFC 7540</a> in 2015.</p><p>HTTP/2 and onwards retained this new standard for connection reuse. More specifically, all subresources on the same domain were able to reuse the same TCP/TLS (or UDP/QUIC) connection without any <a href="https://en.wikipedia.org/wiki/Head-of-line_blocking">head-of-line blocking</a> (at least on the application layer). This resulted in a single connection for all the subresources — reducing extraneous requests on page loads — potentially speeding up some websites and applications.</p><p>Interestingly, the protocol has a lesser-known feature to also enable subresources at <b><i>different</i></b><i> </i><b><i>hostnames</i></b> to be fetched over the <b><i>same</i></b> <b><i>connection</i></b>. We studied the real-world feasibility and benefits of this technique as an effort to improve users' experience for websites across our network.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3tmFcDGsMhGlSKQ3XxEzHs/a10aa68acabb9004a4a25bf82ba9ddc9/image16-1.png" />
            
            </figure><p>Connection Coalescing allows reusing a TLS connection across different domains</p>
    <div>
      <h3>Connection Coalescing</h3>
      <a href="#connection-coalescing">
        
      </a>
    </div>
    <p>The <i>technique</i> is often referred to as <a href="https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/">Connection Coalescing</a> and, to put it simply, is a way to access resources from <i>different hostnames that are accessible from the same web server</i>.</p><p>There are several reasons for why a single server could handle requests for different hosts, ranging from low-cost virtual hosting to the usage of <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDNs</a> and cloud providers (including Cloudflare, that acts as a reverse proxy for approximately <a href="https://www.cloudflare.com/learning/what-is-cloudflare/">25 million Internet properties</a>). Before going into the technical conditions required to enable connection coalescing, we should take a look at some benefits such a strategy can provide.</p><ul><li><p><b>Privacy</b>. When resources at different hostnames are loaded via separate TLS connections, those connections expose metadata to ISPs and other observers via the Server Name Indicator (SNI) field about the destinations that are being contacted (i.e., in the absence of <a href="/esni/">encrypted SNI</a>). This set of exposed SNI’s can allow an on-path adversary to fingerprint traffic and possibly determine user interactions on the webpage. On the other hand, coalesced requests for more than one hostname on a single connection exposes only <b>one</b> destination, and helps avoid such threats.</p></li><li><p><b>Performance</b>. Additional TLS handshakes and TCP connections can incur significant <a href="/how-expensive-is-crypto-anyway/">costs in terms of cpu, memory and other resources</a>. Thus, coalescing requests to use the same connection can optimize resource utilization.</p></li><li><p><b>Resource Prioritization.</b> Multiplexing requests on a single connection means that applications have better visibility and more direct control over how related <a href="/better-http-2-prioritization-for-a-faster-web/">resources are prioritized and scheduled</a>. In the absence of coalescing, the network properties (for example, route congestion) can interfere with the intended order of delivery for resources. This reliability gained through connection coalescing opens up new optimization opportunities to improve web page load times, among other things.</p></li></ul><p>However, along with all these potential benefits, connection coalescing also has some associated risk factors that need to be considered in practice. First, TCP incorporates “fair” congestion control mechanisms — if there are ten connections on the same route, each gets approximately 1/10th of the total bandwidth. So with a route congested and bandwidth restricted, a client relying on <i>multiple connections</i> might be better off (for example, if they have five of the ten connections, their total share of bandwidth would be half). Second, browsers will use different parallelization routines for scheduling requests on multiple connections versus the same connection — it is not immediately clear whether the former or latter would perform better. Third, multiple connections exhibit an inherent form of load balancing for TLS-termination processes. That’s because multiple requests on the same connection must be answered by the same TLS-termination process that holds the session keys (often on the same physical server). So, it is important to study connection coalescing carefully before rolling it out widely.</p><p>With this context in mind, we studied the feasibility of connection coalescing on real-world traffic. More specifically, the two questions we wanted to answer were(a) can we empirically demonstrate and quantify the theoretical benefits of connection coalescing?, and (b) could coalescing cause unintended side effects, such as performance degradation, due to the risks highlighted above?</p><p>In order to answer these questions, we first made the observation that a large number of Cloudflare customers request subresources from <a href="/an-update-on-cdnjs/">cdnjs</a> — which is also powered by Cloudflare. For context, <a href="https://cdnjs.cloudflare.com/">cdnjs</a> has public JavaScript and CSS libraries (like <a href="https://jquery.com/">jQuery</a>), and is used by <a href="https://w3techs.com/technologies/details/cd-cdnjs"><i>more than 12%</i></a> <i>of all websites on the Internet</i>. One popular way these websites include resources from cdnjs is by using <code>&lt;script src="https://cdnjs.cloudflare.com/..." &gt;&lt;/script&gt;</code> HTML tags. But there are other ways as well, such as the usage of <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a> or <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a> APIs. Regardless of the way these resources are included, browsers will need to fetch them for completely loading a website.</p><p>We then identified a list of approximately four thousand websites using Cloudflare (on the <a href="https://www.cloudflare.com/plans/free/">Free plan</a>) that likely used cdnjs. We divided this list of sites into evenly-sized and randomly-picked <i>control</i> and <i>experiment</i> groups. Our plan was to enable coalescing only for the <i>experiment</i> group, so that subresource requests generated from their web pages for cdnjs could reuse existing connections. In this way, we were able to compare results obtained on the <i>experiment</i> group, with the ones for the <i>control</i> group, and attribute any differences observed to connection coalescing.</p><p>In order to signal browsers that the requests can be coalesced, we served cdnjs and the sites from the same IP address in a few regions around the world. This meant the same DNS responses for all the zones that were part of the study — eventually load balanced by our Anycast network. These sites also had TLS certificates that included cdnjs.</p><p>The above two conditions (same IP and compatible certificate) are required to achieve coalescing as per the <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-9.1.1">HTTP/2 spec</a>. However, the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-29#section-3.4">QUIC spec</a> allows coalescing even if only the second condition is met. Major web browsers are <a href="https://mailarchive.ietf.org/arch/msg/quic/0nqKySdzmXK6CwZ9dKfD5GsQgqE/">yet to adopt the QUIC coalescing mechanism</a>, and currently use only the HTTP/2 coalescing logic for both protocols.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6qIQMnxndHLQGdhdmswsxg/da3ba47675985dd6ada032432a9de12e/image14-1.png" />
            
            </figure><p>Requests to Experiment Group Zones and cdnjs being coalesced on the same TLS connection</p>
    <div>
      <h3>Results</h3>
      <a href="#results">
        
      </a>
    </div>
    <p>We started noticing evidence of real-world coalescing from the day our experiment was launched. The following graph shows that approximately 50% of requests to cdnjs from our experiment group sites are coalesced (i.e., their TLS SNI does not equal cdnjs) as compared to 0% of requests from the control group sites.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/A3Z2xGpVTKtXr05t6Vzkd/4f259113d184d2d3b71786e65f805bb3/image2-21.png" />
            
            </figure><p>Coalesced Requests to cdnjs from Control and Experimental Group Zones</p><p>In addition, we conducted active measurements using our private <a href="https://webpagetest.org/">WebPageTest</a> instances at the landing pages of <i>experiment</i> and <i>control</i> sites — using the two well-supported browsers: Google Chrome and Firefox. From our results, Chrome created about 78% fewer TLS connections to cdnjs for our <i>experiment</i> group sites, as compared to the <i>control</i> group. But surprisingly, Firefox created just roughly 22% fewer connections. As TLS handshakes are computationally expensive because they involve cryptographic signatures and key exchange algorithms, fewer handshakes meant less CPU cycles spent by both the client and the server.</p><p>Upon further analysis, we were able to make two observations from the data:</p><ul><li><p>A fraction of sites that never coalesced connections with either browser appeared to load subresources with <a href="https://www.google.com/search?q=CORS&amp;rlz=1C5AVSZ_enUS817US817&amp;oq=CORS&amp;aqs=chrome..69i57j0i433i512j46i199i433i465i512j46i433i512j0i131i433i512j0i433i512j0i512j0i131i433i457j46i433i512j0i433i512.151j0j7&amp;sourceid=chrome&amp;ie=UTF-8">CORS</a> enabled (i.e., <code>&lt;script src="https://cdnjs.cloudflare.com/..." integrity="sha512-894Y..." **crossorigin="anonymous"**&gt;</code>). This is the default way cdnjs recommends inclusion of subresources, as CORS is needed for <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">integrity checks</a> that provide substantial mitigations against script-manipulation attacks. We do not recommend removing this attribute. Our testing also revealed that using <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a> or <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a> APIs to load subresources disabled coalescing as well. It is unclear why browsers choose to not coalesce such connections, and we are in contact with the vendors to find out.</p></li><li><p>Although both Firefox and Chrome coalesced requests for cdnjs on existing connections, the reason for the discrepancy in the number of TLS connections to cdnjs (approximately 78% vs roughly 22%) is because Firefox appears to open new connections even if it does not end up using them.</p></li></ul><p>After evaluating the potential benefits of coalescing, we wanted to understand if coalescing caused any unintended side effects. Hence, the final measurement we conducted was to check whether our experiments were detrimental to a website’s performance. We tracked <a href="/start-measuring-web-vitals-with-browser-insights/">Page Load Times (PLT) and Largest Contentful Paint (LCP)</a> across a variety of stimulated network conditions using both Chrome and Firefox and found the results for experiment vs control group to <i>not</i> be statistically significant.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3mqWfurrAFY6NrvUrO067u/1c55d30632a9bfff09d3592508d7f8e2/image3-19.png" />
            
            </figure><p>Page load times for control and experiment group sites. Each site was loaded once, and the “<i>fullyLoaded</i>” metric from WebPageTest is reported</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>We consider our experimentation successful in determining the feasibility of connection coalescing and highlighting its potential benefits in terms of privacy and performance. More specifically, we observed the privacy benefits of coalescing in more than 50% of requests to cdnjs from real-world traffic. In addition, our active testing demonstrated that browsers create fewer TLS connections with coalescing enabled. Interestingly, our results also revealed that the benefits might not always occur (i.e., CORS-enabled requests, Firefox creating additional TLS connections despite coalescing). Finally, we did not find any evidence that coalescing can cause harm to real-world users’ experience on the Internet.</p><p>Some future directions we would like to explore include:</p><ul><li><p>More aggressive connection reuse with multiple hostnames, while identifying conditions most suitable for coalescing.</p></li><li><p>Understanding how different connection reuse methods compare, e.g., IP-based coalescing vs. use of <a href="https://datatracker.ietf.org/doc/html/rfc8336">Origin Frames</a>, and what effects do they have on user experience over the Internet.</p></li><li><p>Evaluating coalescing support among different browser vendors, and encouraging adoption of HTTP/3 QUIC based coalescing.</p></li><li><p>Reaping the full benefits of connection coalescing by experimenting with custom priority schemes for requests within the same connection.</p></li></ul><p>Please send questions and feedback to <a>ask-research@cloudflare.com</a>. We’re excited to continue this line of work in our effort to help build a better Internet! For those interested in joining our team please visit our <a href="https://www.cloudflare.com/careers/jobs/?department=Technology%20Research&amp;location=default">Careers Page</a>.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Privacy]]></category>
            <category><![CDATA[Performance]]></category>
            <category><![CDATA[Browser Insights]]></category>
            <category><![CDATA[Better Internet]]></category>
            <category><![CDATA[CDNJS]]></category>
            <guid isPermaLink="false">3oUA8RgBt2s0bO1exBJegm</guid>
            <dc:creator>Talha Paracha</dc:creator>
            <dc:creator>Suleman Ahmad</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare's Handling of an RCE Vulnerability in cdnjs]]></title>
            <link>https://blog.cloudflare.com/cloudflares-handling-of-an-rce-vulnerability-in-cdnjs/</link>
            <pubDate>Sat, 24 Jul 2021 12:57:57 GMT</pubDate>
            <description><![CDATA[ Recently, a RCE vulnerability in the way cdnjs’ backend is automatically keeping web resources up to date has been disclosed. Read about how Cloudflare handled the security incident and what will prevent similar exploits in the future. ]]></description>
            <content:encoded><![CDATA[ <p></p><p><a href="https://cdnjs.com/">cdnjs</a> provides JavaScript, CSS, images, and fonts assets for websites to reference with more than 4,000 libraries available. By utilizing cdnjs, websites can load faster with less strain on one’s own origin server as files are served directly from Cloudflare’s edge. Recently, a <a href="https://blog.ryotak.me/post/cdnjs-remote-code-execution-en/">blog post</a> detailed a vulnerability in the way cdnjs’ backend automatically keeps the libraries up to date.</p><p>This vulnerability allowed the researcher to execute arbitrary code, granting the ability to modify assets. This blog post details how Cloudflare responded to this report, including the steps we took to block exploitation, investigate potential abuse, and remediate the vulnerability.</p><p>This vulnerability is not related to Cloudflare CDN. The <i>cdnjs</i> project is a platform that leverages Cloudflare’s services, but the vulnerability described below relates to <i>cdnjs</i>’ platform only. To be clear, no existing libraries were modified using this exploit. The researcher published a new package which demonstrated the vulnerability and our investigation concluded that the integrity of all assets hosted on cdnjs remained intact.</p>
    <div>
      <h3>Disclosure Timeline</h3>
      <a href="#disclosure-timeline">
        
      </a>
    </div>
    <p>As outlined in RyotaK’s blog post, the incident began on 2021-04-06. At around 1100 GMT, RyotaK published a package to npm exploiting the vulnerability. At 1129 GMT, cdnjs processed this package, resulting in a leak of credentials. This triggered GitHub alerting which notified Cloudflare of the exposed secrets.</p><p>Cloudflare disabled the auto-update service and revoked all credentials within an hour. In the meantime, our security team received RyotaK’s remote code execution report through HackerOne. A new version of the auto-update tool which prevents exploitation of the vulnerability RyotaK reported was released within 24 hours.</p><p>Having taken action immediately to prevent exploitation, we then proceeded to redesign the auto-update pipeline. Work to completely redesign it was completed on 2021-06-03.</p>
    <div>
      <h3>Blocking Exploitation</h3>
      <a href="#blocking-exploitation">
        
      </a>
    </div>
    <p>Before RyotaK reported the vulnerability via HackerOne, Cloudflare had already taken action. When GitHub notified us that credentials were leaked, one of our engineers took immediate action and revoked them all. Additionally, the GitHub token associated with this service was automatically revoked by GitHub.</p><p>The second step was to bring the vulnerable service offline to prevent further abuse while we investigated the incident. This prevented exploitation but also made it impossible for legitimate developers to publish updates to their libraries. We wanted to release a fixed version of the pipeline used for retrieving and hosting new library versions so that developers could continue to benefit from caching. However, we understood that a stopgap was not a long term fix, and we decided to review the entire current solution to identify a better design that would improve the overall security of cdnjs.</p>
    <div>
      <h3>Investigation</h3>
      <a href="#investigation">
        
      </a>
    </div>
    <p>Any sort of investigation requires access to logs and all components of our pipeline generate extensive logs that prove valuable for forensics efforts. Logs produced by the auto-update process are collected in a <a href="https://github.com/cdnjs/logs">GitHub repository</a> and sent to our logging pipeline. We also collect and retain logs from cdnjs’ Cloudflare account. Our security team began reviewing this information as soon as we received RyotaK’s initial report. Based on access logs, API token usage, and file modification metadata, we are confident that only RyotaK exploited this vulnerability during his research and only on test files. To rule out abuse, we reviewed the list of source IP addresses that accessed the Workers KV token prior to revoking it and only found one, which belongs to the cdnjs auto-update bot.</p><p>The cdnjs team also reviewed files that were pushed to the <a href="https://github.com/cdnjs/cdnjs">cdnjs/cdnjs GitHub repository</a> around that time and found no evidence of any other abuse across cdnjs.</p>
    <div>
      <h3>Remediating the Vulnerability</h3>
      <a href="#remediating-the-vulnerability">
        
      </a>
    </div>
    <p>Around half of the libraries on cdnjs use <a href="https://www.npmjs.com/">npm</a> to auto-update. The primary vector in this attack was the ability to craft a <code>.tar.gz</code> archive with a symbolic link and publish it to the npm registry. When our pipeline extracted the content it would follow symlinks and overwrite local files using the pipeline user privileges. There are two fundamental issues at play here: an attacker can perform <a href="https://en.wikipedia.org/wiki/Directory_traversal_attack">path traversal</a> on the host processing untrusted files, and the process handling the compressed file is <a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege">overly privileged</a>.</p><p>We addressed the path traversal issue by checking that the destination of each file in the tarball will be contained within the target directory that the update process has designated for that package. If the file’s <a href="https://en.wikipedia.org/wiki/Canonicalization">full canonical path</a> doesn’t begin with the destination directory’s full path, we log this as a warning and skip extracting that file. This works fairly well, but as noted in the <a href="https://github.com/cdnjs/tools/pull/220/files#diff-0df1c31d75e0fcc18581b25b3e3e8f7584e0c6acdf38eef60ddcd06d01ac3734R59-R63">comment</a> above this check, if the compressed file uses UTF-8 encoding for filenames, this check may not properly canonicalize the path. If this canonicalization does not occur, the path may contain path traversal, even though it starts with the correct destination path.</p><p>To ensure that other vulnerabilities in cdnjs’ publication pipeline cannot be exploited, we configured an <a href="https://github.com/cdnjs/bot-ansible/pull/24/files">AppArmor profile</a> for it. This limits the <a href="https://man7.org/linux/man-pages/man7/capabilities.7.html">capabilities</a> of the service, so even if an attacker successfully instructed the process to perform an action, the operating system (kernel / security feature) will not allow any action outside of what it is allowed to do.</p><p>For illustration, here’s an example:</p>
            <pre><code>/path/to/bin {
  network,
  signal,
  /path/to/child ix,
  /tmp/ r,
  /tmp/cache** rw,
  ...
}</code></pre>
            <p>In this example, we only allow the binary (/path/to/bin) to:</p><ul><li><p>access all networking</p></li><li><p>use all signals</p></li><li><p>execute /path/to/child (which will inherit the AppArmor profile)</p></li><li><p>read from /tmp</p></li><li><p>read+write under /tmp/cache.</p></li></ul><p>Any attempt to access anything else will be denied. You can find the complete list of capabilities and more information on <a href="https://manpages.ubuntu.com/manpages/precise/en/man5/apparmor.d.5.html">AppArmor’s manual page</a>.</p><p>In the case of cdnjs’ autoupdate tool, we limit execution of applications to a very specific set, and we limit where files can be written.</p><p>Fixing the path traversal and implementing the AppArmor profile prevents similar issues from being exploited. However, having a single layer of defense wasn’t enough. We decided to completely redesign the auto-update process entirely to isolate each step, as well as each library it processes, thus preventing this entire class of attacks.</p>
    <div>
      <h3>Redesigning the system</h3>
      <a href="#redesigning-the-system">
        
      </a>
    </div>
    <p>The main idea behind the redesign of the pipeline was to move away from the monolithic auto-update process. Instead, various operations are done using microservices or daemons which have well-defined scopes. Here’s an overview of the steps:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/NaGyDtiWkMV4J2XvfbReq/4f4aafe30c6fbe07bfd684845dafef3d/image1-18.png" />
            
            </figure><p>First, to detect new library versions, two daemons (for both npm and git based updates) are regularly running. Once a new version has been detected, the files will be downloaded as an archive and placed into the incoming storage bucket.</p><p>Writing a new version in the incoming bucket triggers a function that adds all the information we need to update the library. The function also generates a signed URL allowing for writing in the outgoing bucket, but only in a specific folder for a given library, reducing the blast radius. Finally, a message is placed into a queue to indicate that the new version of the given library is ready to be published.</p><p>A daemon listens for incoming messages and spawns an unprivileged Docker container to handle dangerous operations (archive extraction, minifications, and compression). After the sandbox exits, the daemon will use the signed URL to store the processed files in the outgoing storage bucket.</p><p>Finally, multiple daemons are triggered when the finalized package is written to the outgoing bucket. These daemons publish the assets to cdnjs.cloudflare.com and to the main <a href="https://github.com/cdnjs/cdnjs">cdnjs repository</a>. The daemons also publish the version specific URL, cryptographic hash, and other information to Workers KV, cdnjs.com, and the <a href="https://cdnjs.com/api">API</a>.</p><p>In this revised design, exploiting a similar vulnerability would happen in the sandbox (Docker container) context. The attacker would have access to container files, but nothing else. The container is minimal, ephemeral, has no secrets included, and is dedicated to a single library update, so it cannot affect other libraries’ files.</p>
    <div>
      <h3>Our Commitment to Security</h3>
      <a href="#our-commitment-to-security">
        
      </a>
    </div>
    <p>Beyond maintaining a vulnerability disclosure program, we regularly perform internal security reviews and hire third-party firms to audit the software we develop. But it is through our vulnerability disclosure program that we receive some of the most interesting and creative reports. Each report has helped us improve the security of our services. In this case, we worked with RyotaK to not only address the vulnerability, but to also ensure that their blog post was detailed and accurate. We invite those that find a security issue in any of Cloudflare’s services to report it to us through <a href="https://hackerone.com/cloudflare">HackerOne</a>.</p> ]]></content:encoded>
            <category><![CDATA[CDNJS]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Bug Bounty]]></category>
            <guid isPermaLink="false">666ctQ9OY5rCiI6GZyKm9G</guid>
            <dc:creator>Jonathan Ganz</dc:creator>
            <dc:creator>Thomas Calderon</dc:creator>
            <dc:creator>Sven Sauleau</dc:creator>
        </item>
        <item>
            <title><![CDATA[Migrating cdnjs to serverless with Workers KV]]></title>
            <link>https://blog.cloudflare.com/migrating-cdnjs-to-serverless-with-workers-kv/</link>
            <pubDate>Thu, 10 Sep 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare powers cdnjs, an open-source project that delivers popular JavaScript libraries to over 11% of websites. Today, we are excited to announce its migration to a serverless infrastructure using Cloudflare Workers and its distributed key-value store Workers KV! ]]></description>
            <content:encoded><![CDATA[ <p>Cloudflare powers <a href="https://cdnjs.com/">cdnjs</a>, an open-source project that accelerates websites by delivering popular JavaScript libraries and resources via <a href="https://www.cloudflare.com/cdn/">Cloudflare’s network</a>. Since <a href="/an-update-on-cdnjs/">our major update in December</a>, we focused on remodelling cdnjs for scalability and resilience. Today, we are excited to announce how Cloudflare delivers cdnjs—a migration to a serverless infrastructure using <a href="https://developers.cloudflare.com/workers/">Cloudflare Workers</a> and its distributed key-value store <a href="https://developers.cloudflare.com/workers/reference/storage">Workers KV</a>!</p>
    <div>
      <h3>What is cdnjs?</h3>
      <a href="#what-is-cdnjs">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/K5YOmwNbwMpTE8ILtKovN/a242c00ce389b1e3365a3e8ffb062d01/imagesmall.png" />
            
            </figure><p>For those unfamiliar, cdnjs is an acronym describing a Content Delivery Network (CDN) for JavaScript (JS). A <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDN</a> simply refers to a geographically distributed network of servers that provide Internet content, whether it is memes, cat videos, or HTML pages. In our case, the CDN refers to Cloudflare’s ever <a href="/cloudflare-network-expands-to-more-than-100-countries/">expanding network</a> of over 200 globally distributed data centers.</p><p>And here’s why this is relevant to you: it makes page load times lightning-fast. Virtually every website you visit needs to fetch JS libraries in order to load, including this one. Let’s say you visit a Sydney-based website that contains a local file from jQuery, a popular library found in <a href="https://w3techs.com/technologies/details/js-jquery">76.2%</a> of websites. If you are located in New York, you may notice a delay, as it can easily exceed 300ms to fetch the file—not to mention the time it takes for the round trips involved with the <a href="/tls-1-3-overview-and-q-and-a/">TLS handshake</a>. However, if the website references jQuery using <a href="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js">cdnjs.cloudflare.com</a>, you can retrieve the file from the closest Cloudflare data center in Buffalo, reducing the latency to a blazing 20ms.</p><p>While cdnjs operates behind the scenes, it is used by <a href="https://w3techs.com/technologies/overview/content_delivery">over 11%</a> of websites, making the Internet a much faster and more reliable place. In July, cdnjs served almost <a href="https://github.com/cdnjs/cf-stats/blob/master/2020/cdnjs_July_2020.md">190 billion requests</a>—an enormous 3.46PB of data.</p>
    <div>
      <h3>Where are the files stored?</h3>
      <a href="#where-are-the-files-stored">
        
      </a>
    </div>
    <p><img src="http://staging.blog.mrk.cfdata.org/content/images/2020/09/image5-2.png" /></p><p>While cdnjs speeds up the Internet, it certainly isn’t magic!</p><p>Historically, a number of <a href="https://www.cloudflare.com/load-balancing/">load-balanced</a> machines at one of Cloudflare’s core data centers would periodically pull cdnjs files from a backing store, acting as the origin for cdnjs.cloudflare.com. When a new file is requested, it is <a href="https://www.cloudflare.com/learning/cdn/what-is-caching/">cached</a> by Cloudflare, allowing it to be fetched quickly from any of our data centers.</p><p>The backing store is a catalogue of JS, CSS, and other web libraries in the form of an open-source <a href="https://github.com/">GitHub</a> repository. What this means is that anyone—including you—can contribute to it, subject to review and other processes.</p><p>However, until recently, these existing operations were very labor intensive and fragile.</p><p>This blog post will explain why we changed the infrastructure behind cdnjs to make it faster, more reliable, and easier to maintain. First, we will discuss how the community used to contribute to cdnjs, outlining the pains and concerns of the old system. Then, we will explore the benefits of migrating to Workers KV. After, we will dive into the new architecture, as well as upgrades to the website and cdnjs API. Finally, we will review the history of cdnjs, and where it is headed in the future.</p>
    <div>
      <h3>If you think you know how to make a PR, think again</h3>
      <a href="#if-you-think-you-know-how-to-make-a-pr-think-again">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Qz4kp8D2lbh2dSPTBQizG/1bcf42ec9c4b6f0553c38ce59666b707/image1-1.png" />
            
            </figure><p>For the non-technical reader, a pull request (PR) is a request to merge changes you’ve made to a repository. Traditionally, if you wanted to include your JavaScript library in cdnjs, you would first create a PR on GitHub to <a href="https://github.com/cdnjs/cdnjs">cdnjs/cdnjs</a> with a JSON file describing your package and additional files for any version you wished to include. Once your PR was approved by our <a href="https://github.com/PeterBot">old bot</a>, manually reviewed, and then merged by a maintainer, your package would be integrated with cdnjs.</p><p>Sounds easy, right? You can just fork the repo, clone it, and copy paste a few files, no?</p><p>Exactly. Contributing was easy if you had several hours to burn, a case-sensitive file system, and a couple hundred gigabytes of free disk space to <a href="https://git-scm.com/docs/git-clone">git clone</a> the 300GB repo. If you were short on time—no problem, you could always use your advanced knowledge of <a href="https://git-scm.com/docs/git-sparse-checkout">git sparse-checkout</a> to get the job done. Don’t know git? Just add one file at a time manually through GitHub’s UI.</p><p>I think you get the point. I know I certainly did when I naively spent 10 hours cloning the repo, only to discover that macOS is case-insensitive by default.</p><p>However, updating cdnjs was not only difficult for the contributors, but also the maintainers. Historically, the community was able to contribute version files directly, which could potentially be malicious. This created lots of work for maintainers, requiring them to inspect each file manually, <a href="https://man7.org/linux/man-pages/man1/diff.1.html">diffing</a> files against the official library source and running malware checks.So how did packages update once they were in cdnjs? In the JSON file describing each package, there was an optional auto-update definition telling the bot where to look for new versions of the library. If present, when your package released a new version from npm or GitHub, the bot would download it, pushing the files to <a href="https://github.com/cdnjs/cdnjs">cdnjs/cdnjs</a> and computed <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">Subresource Integrity</a> (SRI) hashes to <a href="https://github.com/cdnjs/SRIs">cdnjs/SRIs</a>. If the auto-update property was missing, it would be your responsibility to make manual PRs to update cdnjs with any future versions.</p>
    <div>
      <h3>A wake-up call for cdnjs</h3>
      <a href="#a-wake-up-call-for-cdnjs">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Bh8OS2VHZy5FKAySbhQns/84626f199211f856b3f230fcb109c161/image6-1-4.png" />
            
            </figure><p>In April, during maintenance at one of our core data centers, a technician accidentally disconnected the cables supplying all external connections to our other data centers, causing the data center to go offline for approximately four hours. <a href="/cloudflare-dashboard-and-api-outage-on-april-15-2020/">This incident</a> served as the first wake-up call for cdnjs, especially since the affected data center housed the primary cdnjs origin web servers. In this case, we did have a backup running on an external provider, but what really saved us was Cloudflare’s global cache, which minimized the impact of the outage as only uncached assets failed to load.</p><p>We started to think about how we can improve both the reliability and performance of how we serve cdnjs. We went straight to <a href="https://workers.cloudflare.com/">Cloudflare Workers</a>, our own platform for developing on the <a href="https://www.cloudflare.com/learning/cdn/glossary/edge-server/">edge</a>. One powerful tool built into Workers is <a href="https://developers.cloudflare.com/workers/reference/storage">Workers KV</a>—a low-latency, globally distributed key-value store optimized for high-read applications.</p><p>We put two and two together, realizing that instead of pulling the <a href="https://github.com/cdnjs/cdnjs">cdnjs/cdnjs</a> repository and serving files from disk, we could cut the physical machines out entirely, distributing the data around the world and serving files straight from the edge. That way, cdnjs would be able to recover from any origin data center failure, while also increasing its scalability.</p>
    <div>
      <h3>Workers KV to the rescue</h3>
      <a href="#workers-kv-to-the-rescue">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6dAu3V0R16Ugbf2Ad0nh4f/3ce544c6aa6c9558fdfbe686ff5ef640/image3-3.png" />
            
            </figure><p>At first glance, the decision to use Workers KV was a no-brainer. Since files in cdnjs never change but require frequent reads, Workers KV was a perfect fit.</p><p>However, as we planned our migration, we became concerned that with over 7 million assets in cdnjs, there would undoubtedly exist files that exceed <a href="https://developers.cloudflare.com/workers/about/limits/">Workers KV’s 10MiB value limit</a>. After investigating, we discovered that several hundred cdnjs files were oversized, the majority being <a href="https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map">JavaScript Source Maps</a>.</p><p>Then the idea hit us. We could store compressed versions of cdnjs files in Workers KV, not only solving our oversized file issue, but also optimizing how we serve files.</p><p>If you pay the Internet bill, you’ll know that <a href="/the-relative-cost-of-bandwidth-around-the-world/">bandwidth is expensive</a>! For this reason, all modern browsers will try to <a href="/efficiently-compressing-dynamically-generated-53805/">fetch compressed web content</a> whenever it is available. Similarly, within Cloudflare we often <a href="/results-experimenting-brotli/">experiment with on-the-fly compression</a> to reduce our bandwidth, always serving compressed content to the eyeball when it is accepted. As a result, we decided to compress all cdnjs files ahead of time, writing them to Workers KV with both optimal <a href="https://github.com/google/brotli">Brotli</a> and <a href="https://www.gzip.org/">gzip</a> forms. That way, we could increase the compression level compared to on-the-fly compression as we no longer have the latency requirements.</p><p>This means we now serve cdnjs files faster and smaller!</p>
    <div>
      <h3>A complete makeover for cdnjs</h3>
      <a href="#a-complete-makeover-for-cdnjs">
        
      </a>
    </div>
    <p><a href="http://staging.blog.mrk.cfdata.org/content/images/2020/09/image7-1.png"><img src="http://staging.blog.mrk.cfdata.org/content/images/2020/09/image7-1.png" /></a></p><p>Today, if you want to include your JavaScript library in cdnjs, you first create a PR on GitHub to our new repository <a href="https://github.com/cdnjs/packages">cdnjs/packages</a>. The repo is easily cloneable at 50MB and consists of thousands of JSON files, each describing a cdnjs package and how it is auto-updated from npm or git. Once your file is validated by our automated CI—powered by a <a href="https://github.com/cdnjs/tools">new bot</a>—and merged by a maintainer, your package would be automatically enrolled in our auto-update service.</p><p>In the new system, security and maintainability are prioritized. For starters, cdnjs version files are created by our bot, minimizing the possibility of human error when merging a new version. While the JSON files in <a href="https://github.com/cdnjs/packages">cdnjs/packages</a> are added by error-prone humans, they are inspected by our bot before being approved by a maintainer. Each file is automatically validated against a <a href="https://github.com/cdnjs/tools/blob/master/schema_human.json">JSON schema</a>, as well as checked for popularity on npm or GitHub.</p><p>When the bot discovers a new release, it pushes Brotli and gzip-compressed versions of the files to a files namespace in Workers KV. With each entry, the bot writes some <a href="/catching-up-with-workers-kv/">metadata in Workers KV</a> for the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag">ETag</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified">Last-Modified</a> HTTP headers. Similar to before, the bot also computes <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">Subresource Integrity</a> (SRI) hashes of the uncompressed files, but now pushes them instead to a SRIs namespace in Workers KV.</p><p>Then, when a new file is requested from cdnjs.cloudflare.com, a <a href="https://developers.cloudflare.com/workers/">Cloudflare Worker</a> will inspect the client’s <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding">Accept-Encoding</a> header, fetching either the Brotli or gzip-compressed version with its ETag and Last-Modified metadata from Workers KV. As the compressed file travels back through Cloudflare, it is cached for future requests and uncompressed on-the-fly if needed.</p><p>At the moment, there are still a handful of files exceeding Workers KV’s size limit. Consequently, if the Cloudflare Worker fails to retrieve a file from Workers KV, it is fetched from the origin backed by the original git repo. In the coming months, we plan on gradually removing this infrastructure.</p>
    <div>
      <h3>Scaling the website and API</h3>
      <a href="#scaling-the-website-and-api">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2q1lBMUDzWZUSCs9rMRTIw/a0b9baf89cd1056752a84566fe31dda8/image2.gif" />
            
            </figure><p>Besides the core cdnjs infrastructure, many of its other components received upgrades as well!</p><p>On the cdnjs project’s <a href="https://cdnjs.com/">homepage</a>, you will be greeted by a slick <a href="https://github.com/cdnjs/static-website">new beta website</a> built by <a href="https://github.com/mattipv4">Matt</a>. Constructed with <a href="https://vuejs.org/">Vue</a> and <a href="https://nuxtjs.org/">Nuxt</a>, the beta website is powered entirely by the <a href="https://cdnjs.com/api">cdnjs API</a>. As a result, it is always up-to-date with the latest package information and requires low resource usage to serve the site—which runs completely on the client-side after the first page load—helping us scale with cdnjs’s never-ending growth.</p><p>In fact, the cdnjs API also strengthened its scalability, benefitting from a serverless architecture close to the one we have seen with cdnjs and Workers KV.</p><p>Before migrating to Workers KV, the cdnjs API relied on a regularly scheduled process that involved generating about 300MB of metadata. The cdnjs API’s backend would then fetch this enormous “package.min.js” file into memory and use it to operate the API. Similarly, file SRIs were pushed to <a href="https://github.com/cdnjs/SRIs">cdnjs/SRIs</a>, which was cloned by the API locally to serve SRI responses.</p><p>After all cdnjs files (within the permitted size limit) were moved to Workers KV, these legacy processes became unsustainable, requiring millions of reads and an unreasonable amount of time. Therefore, we decided to upload all metadata found into Workers KV. We split the metadata into four namespaces—one for package-level metadata, one for version-specific metadata, one containing aggregated metadata, and one for file SRIs.</p><p>Similar to cdnjs’s serverless design, a Cloudflare Worker sits on top of <a href="http://metadata.speedcdnjs.com/packages">metadata.speedcdnjs.com</a>, serving data from Workers KV using several public endpoints. Currently, the cdnjs API is fully integrated with these endpoints, which provide an elegant solution as cdnjs continues to scale.</p>
    <div>
      <h3>Transparency and the future of cdnjs</h3>
      <a href="#transparency-and-the-future-of-cdnjs">
        
      </a>
    </div>
    <p>Since its birth in January 2011, cdnjs has always been deeply rooted in transparency, deriving its strength from the community. Even when cdnjs exploded in size and its founders Ryan Kirkman and Thomas Davis <a href="/cdnjs-community-moderated-javascript-librarie/">teamed up with us in June 2011</a>, the project remained entirely open-source on <a href="https://github.com/cdnjs/">GitHub</a>.</p><p>As the years passed, it became harder for the founders to stay active, heavily depending on the community for support. With a nearly nonexistent budget and little access to the repository, core cdnjs maintainers were challenged every day to keep the project alive.</p><p>Last year, this led us to contact the founders, <a href="https://news.ycombinator.com/item?id=21416614">who were happy to have our assistance with the project</a>. With Cloudflare’s increased role, cdnjs is as stable as ever, with <a href="https://cdnjs.com/about">active members</a> from both Cloudflare and the community.</p><p>However, as we remove our reliance on the legacy system and store files in Workers KV, there are concerns that cdnjs will become proprietary. Don’t worry, we are working hard to ensure that cdnjs remains as transparent and open-source as possible. To help the community audit updates to Workers KV, there is a new repository, <a href="https://github.com/cdnjs/logs">cdnjs/logs</a>, which is used by the bot to log all Workers KV-related events. Furthermore, anyone can validate the integrity of cdnjs files by fetching SRIs from the cdnjs API.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Overall, this past year has been a turbulent time for cdnjs, but all of its shortcomings have acted as red flags to help us build a better system. Most recently, we have mitigated the risks of depending on physical machines at a single location, migrating cdnjs to a serverless infrastructure where its files are stored in <a href="https://developers.cloudflare.com/workers/reference/storage">Workers KV</a>.</p><p>Today, cdnjs is in good hands, and is not going away anytime soon. Shout out especially to the maintainers <a href="https://github.com/xtuc">Sven</a> and <a href="https://github.com/mattipv4">Matt</a> for creating tons of momentum with the project, working on everything from scaling cdnjs to editing this post.</p><p>Moving forward, we are committed to making cdnjs as transparent as possible. As we continue to improve cdnjs, we will release more blog posts to keep the community up to date. If you are interested, please subscribe to our blog. After all, it is the community that makes cdnjs possible! A special thanks to our active GitHub contributors and members of the <a href="https://github.com/cdnjs/cdnjs/discussions/">cdnjs Community Forum</a> for sticking with us!</p> ]]></content:encoded>
            <category><![CDATA[CDNJS]]></category>
            <category><![CDATA[Cloudflare Workers KV]]></category>
            <category><![CDATA[Open Source]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Serverless]]></category>
            <guid isPermaLink="false">2YoV0y94C9jANAkQJ2V0TA</guid>
            <dc:creator>Tyler Caslin</dc:creator>
        </item>
        <item>
            <title><![CDATA[JavaScript Libraries Are Almost Never Updated Once Installed]]></title>
            <link>https://blog.cloudflare.com/javascript-libraries-are-almost-never-updated/</link>
            <pubDate>Mon, 27 Jan 2020 16:48:58 GMT</pubDate>
            <description><![CDATA[ An analysis, based on CDNJS data, of when and if JavaScript libraries are updated after being installed onto websites. ]]></description>
            <content:encoded><![CDATA[ <p>Cloudflare helps run <a href="https://cdnjs.com/">CDNJS</a>, a very popular way of including JavaScript and other frontend resources on web pages. With the CDNJS team’s permission we collect anonymized and aggregated data from CDNJS requests which we use to understand how people build on the Internet. Our analysis today is focused on one question: once installed on a site, do JavaScript libraries ever get updated?</p><p>Let’s consider jQuery, the most popular JavaScript library on Earth. This chart shows the number of requests made for a selected list of jQuery versions over the past 12 months:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78wDloZEiwcRwOAIt0a9i9/72f4ca0a07fcfe78bf499b353540cccd/1-1.png" />
            
            </figure><p>Spikes in the CDNJS data as you see with version 3.3.1 are not uncommon as very large sites add and remove CDNJS script tags.</p><p>We see a steady rise of version 3.4.1 following its release on May 2nd, 2019. What we don’t see is a substantial decline of old versions. Version 3.2.1 shows an average popularity of 36M requests at the beginning of our sample, and 29M at the end, a decline of approximately 20%. This aligns with a <a href="http://informationr.net/ir/9-2/paper174.html#2002">corpus of research</a> which shows the average website lasts somewhere between two and four years. What we don’t see is a decline in our old versions which come close to the volume of growth of new versions when they’re released. In fact the release of 3.4.1, as popular as it quickly becomes, doesn’t change the trend of old version deprecation at all.</p><p>If you’re curious, the oldest version of jQuery CDNJS includes is 1.10.0, released on May 25, 2013. The project still gets an average of 100k requests per day, and the sites which use it are growing in popularity:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5DVnwBygO53F6wCoy1lccv/3298e8dc13a983e3a3cf5de85991cd0e/2-1.png" />
            
            </figure><p>To confirm our theory, let’s consider another project, <a href="https://greensock.com/tweenmax/">TweenMax</a>:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/17MaW2IADBKgVYgVcbQfJA/40c25be214ee62b3157540372ffb959f/3-1.png" />
            
            </figure><p>As this package isn’t as popular as jQuery, the data has been smoothed with a one week trailing average to make it easier to identify trends.</p><p>Version 1.20.4 begins the year with 18M requests, and ends it with 14M, a decline of about 23%, again in alignment with the loss of websites on the Internet. The growth of 2.1.3 shows clear evidence that the release of a new version has almost no bearing on the popularity of old versions, the trend line for those older versions doesn’t change even as 2.1.3 grows to 29M requests per day.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6LAcaWQJZ5P02U6pKMX4cP/ffc8d229444938c23ef03f09a3af6db0/4-1.png" />
            
            </figure><p>One conclusion is whatever libraries you publish will exist on websites forever. The underlying web platform consequently must support aged conventions indefinitely if it is to continue supporting the full breadth of the web.</p><p>Cloudflare is very interested in how we can contribute to a web which is kept up-to-date. Please make suggestions in the comments below.</p> ]]></content:encoded>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[CDNJS]]></category>
            <category><![CDATA[Data]]></category>
            <guid isPermaLink="false">db038KkCMtqjJlwaumhOn</guid>
            <dc:creator>Zack Bloom</dc:creator>
        </item>
        <item>
            <title><![CDATA[An Update on CDNJS]]></title>
            <link>https://blog.cloudflare.com/an-update-on-cdnjs/</link>
            <pubDate>Thu, 19 Dec 2019 19:30:19 GMT</pubDate>
            <description><![CDATA[ CDNJS powers over 10% of the web. A month ago it needed our help, now it needs yours. ]]></description>
            <content:encoded><![CDATA[ <p>When you loaded this blog, a file was delivered to your browser called jquery-3.2.1.min.js. jQuery is a library which makes it easier to build websites, and was at one point included on as many as <a href="https://w3techs.com/technologies/details/js-jquery">74.1%</a> of all websites. A full eighteen million sites include jQuery and other libraries using one of the most popular tools on Earth: <a href="https://cdnjs.com/">CDNJS</a>. Beginning about a month ago Cloudflare began to take a more active role in the operation of CDNJS. This post is here to tell you more about CDNJS’ history and explain why we are helping to manage CDNJS.</p>
    <div>
      <h2>What CDNJS Does</h2>
      <a href="#what-cdnjs-does">
        
      </a>
    </div>
    <p>Virtually every site is composed of not just the code written by its developers, but also dozens or hundreds of libraries. These libraries make it possible for websites to extend what a web browser can do on its own. For example, libraries can allow a site to include powerful <a href="https://d3js.org/">data visualizations</a>, respond to <a href="https://www.meteor.com/">user input</a>, or even <a href="https://instant.page/">get more performant</a>.</p><p>These libraries created wondrous and magical new capabilities for web browsers, but they can also cause the size of a site to explode. Particularly a decade ago, connections were not always fast enough to permit the use of many libraries while maintaining performance. But if so many websites are all including the same libraries, why was it necessary for each of them to load their own copy?</p><p>If we all load jQuery from the same place the browser can do a much better job of not actually needing to download it for every site. When the user visits the first jQuery-powered site it will have to be downloaded, but it will already be cached on the user's computer for any subsequent jQuery-powered site they might visit.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5KvbGCC3AOaU9YfFjRp4Ji/707e8cbacf87ff72fdd26bd197b7f925/2-1.png" />
            
            </figure><p>The first visit might take time to load:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/zjCDXJufSaYaIhnivnaju/956ee4881f53e4be9f49871b4ba1fb73/Screen-Shot-2019-12-17-at-2.25.49-PM.png" />
            
            </figure><p>But any future visit to any website pointing to this common URL would already be cached:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3NSQiCFdy2m4kJkHkARFoh/a86141bb665b85ca46d1d77cd95e35ad/Screen-Shot-2019-12-17-at-2.26.09-PM.png" />
            
            </figure>
            <pre><code>&lt;!-- Loaded only on my site, will need to be downloaded by every user --&gt;
&lt;script src="./jquery.js"&gt;&lt;/script&gt;

&lt;!-- Loaded from a common location across many sites --&gt;
&lt;script src="https://cdnjs.cloudflare.com/jquery.js"&gt;&lt;/script&gt;</code></pre>
            <p>Beyond the performance advantage, including files this way also made it very easy for users to experiment and create. When using a web browser as a creation tool users often didn't have elaborate build systems (this was also before <a href="https://www.npmjs.com/">npm</a>), so being able to include a simple script tag was a boon. It's worth noting that it's not clear a massive performance advantage was ever actually provided by this scheme. It is becoming even less of a performance advantage now that browser vendors are beginning to use separate cache's for each website you visit, but with millions of sites using CDNJS there's no doubt it is a critical part of the web.</p>
    <div>
      <h2>A CDN for all of us</h2>
      <a href="#a-cdn-for-all-of-us">
        
      </a>
    </div>
    <p>My first <a href="https://github.com/cdnjs/cdnjs/pull/1369">Pull Request</a> into the CDNJS project was in 2013. Back then if you created a JavaScript project it wasn't possible to have it included in the jQuery CDN, or the ones provided by large companies like Google and Microsoft. They were only for big, important, projects. Of course, however, even the biggest project starts small. The community needed a <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDN</a> which would agree to host nearly all JavaScript projects, even the ones which weren't world-changing (yet). In 2011, that project was launched by Ryan Kirkman and Thomas Davis as <a href="https://cdnjs.com">CDNJS</a>.</p><p>The project was quickly wildly successful, far beyond their expectations. Their CDN bill quickly began to skyrocket (it would now be over a million dollars a year on AWS). Under the threat of having to shut down the service, Cloudflare was approached by the CDNJS team to see if we could help. We agreed to support their efforts and created cdnjs.cloudflare.com which serves the CDNJS project free of charge.</p><p>CDNJS has been astonishingly successful. The project is currently installed on over eighteen million websites (<a href="https://w3techs.com/technologies/overview/content_delivery">10%</a> of the Internet!), offers files totaling over <a href="https://cdnjs.com/git_stats/cdnjs/general.html">1.5 billion lines of code</a>, and serves over 173 billion requests a month. CDNJS only gets more popular as sites get larger, with <a href="https://trends.builtwith.com/cdn/CDN-JS">34%</a> of the top 10k websites using the service. Each month we serve almost three petabytes of JavaScript, CSS, and other resources which power the web via cdnjs.cloudflare.com.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7nE6O3729XDte6o95NNThA/b91592cf9679b14f5b4aef57db8afe86/pasted-image-0-1.png" />
            
            </figure><p>Spikes can happen when a very large or popular site installs CDNJS, or when a misbehaving web crawler discovers a CDNJS link.</p><p>The future value of CDNJS is now in doubt, as web browsers are beginning to use a <a href="https://www.chromestatus.com/feature/5730772021411840">separate cache</a> for every website you visit. It is currently used on such a <a href="https://w3techs.com/technologies/overview/content_delivery">wide swath of the web</a>, however, it is unlikely it will be disappearing any time soon.</p>
    <div>
      <h2>How CDNJS Works</h2>
      <a href="#how-cdnjs-works">
        
      </a>
    </div>
    <p>CDNJS starts with a GitHub repo. That project contains every file served by CDNJS, at every version which it has ever offered. That’s 182 GB without the commit history, over five million files, and over 1.5 billion lines of code.</p><p>Given that it stores and delivers versioned code files, in many ways it was the Internet’s first JavaScript package manager. Unlike other package managers and even other CDNs everything CDNJS serves is publicly versioned. All 67,724 commits! This means you as a user can verify that you are being served files which haven’t been tampered with.</p><p>To make changes to CDNJS a commit has to be made. For new projects being added to CDNJS, or when projects change significantly, these commits are made by humans, and get reviewed by other humans. When projects just release new versions there is a bot made by <a href="https://twitter.com/PeterDaveHello">Peter</a> and maintained by <a href="http://github.com/xtuc">Sven</a> which sucks up changes from npm and automatically creates commits.</p><p>Within Cloudflare’s infrastructure there is a set of machines which are responsible for pulling the latest version of the repo periodically. Those machines then become the origin for cdnjs.cloudflare.com, with <a href="https://www.cloudflare.com/load-balancing/">Cloudflare’s Global Load Balancer</a> automatically handling failures. Cloudflare’s cache automatically stores copies of many of the projects making it possible for us to deliver them quickly from all 195 of our data centers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/y6zjzefb5QVkla0fcCbUA/029fedc23230e957333de2c912df2113/1-with-arrow-v2-1.png" />
            
            </figure>
    <div>
      <h2>The Internet on a Shoestring Budget</h2>
      <a href="#the-internet-on-a-shoestring-budget">
        
      </a>
    </div>
    <p>The CDNJS project has always been administered independently of Cloudflare. In addition to the founders, the project has additionally been maintained by exceptionally hard-working caretakers like <a href="https://twitter.com/PeterDaveHello">Peter</a> and <a href="https://twitter.com/MattIPv4">Matt Cowley</a>. Maintaining a single repo of nearly every frontend project on Earth is no small task, and it has required a substantial amount of both manual work and bot development.</p><p>Unfortunately approximately thirty days ago one of those bots stopped working, preventing updated projects from appearing in CDNJS. The bot's open-source maintainer was not able to invest the time necessary to keep the bot running. After several weeks we were asked by the community and the CDNJS founders to take over maintenance of the CDNJS repo itself. This means the Cloudflare engineering team is taking responsibility for keeping the contents of <a href="https://github.com/cdnjs/cdnjs">github.com/cdnjs/cdnjs</a> up to date, in addition to ensuring it is correctly served on cdnjs.cloudflare.com.</p><p>We agreed to do this because we were, frankly, scared. Like so many open-source projects CDNJS was a critical part of our world, but wasn’t getting the attention it needed to survive. The Internet relies on CDNJS as much as on any other single project, losing it or allowing it to be commandeered would be catastrophic to millions of websites and their visitors. If it began to fail, some sites would adapt and update, others would be broken forever.</p><p>CDNJS has always been, and remains, a project for and by the community. We are invested in making all decisions in a transparent and inclusive manner. If you are interested in contributing to CDNJS or in the topics we're currently discussing please visit the <a href="https://github.com/cdnjs/cdnjs/issues">CDNJS Github Issues</a> page.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1RYsRv22prgSJsOzeUTFMG/97b5dec8a319da206c50d43cb78dbd72/pasted-image-0-1-1.png" />
            
            </figure>
    <div>
      <h2>A Plan for the Future</h2>
      <a href="#a-plan-for-the-future">
        
      </a>
    </div>
    <p>One example of an area where we could use your help is in charting a path towards a CDNJS which requires less manual moderation. Nothing can replace the intelligence and creativity of a human (yet), but for a task like managing what resources go into a CDN, it is error-prone and time-consuming. At present a human has to review every new project to be included, and often has to take additional steps to include new versions of a project.</p><p>As a part of our analysis of the project we examined a snapshot of the still-open PRs made against CDNJS for several months:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ffwfsahT0occRgh467Exy/c4441f487765636a0e05a36feebdb375/imageLikeEmbed.png" />
            
            </figure><p>The vast majority of these PRs were changes which ultimately passed the automated review but nevertheless couldn't be merged without manual review.</p><p>There is consensus that we should move to a model which does not require human involvement in most cases. We would love your input and collaboration on the best way for that to be solved. If this is something you are passionate about, please <a href="https://github.com/cdnjs/cdnjs/issues/13613">contribute here</a>.</p><p>Our plan is to support the CDNJS project in whichever ways it requires for as long as the Internet relies upon it. We invite you to use CDNJS in your next project with the full assurance that it is backed by the same network and team who protect and accelerate over twenty million of your favorite websites across the Internet. We are also planning more posts diving further into the CDNJS data, subscribe to this blog if you would like to be notified upon their release.</p> ]]></content:encoded>
            <category><![CDATA[CDNJS]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Open Source]]></category>
            <category><![CDATA[Developers]]></category>
            <guid isPermaLink="false">6GUF8P2EMzt01zbVqpBOwx</guid>
            <dc:creator>Zack Bloom</dc:creator>
        </item>
        <item>
            <title><![CDATA[CDNJS: The Fastest Javascript Repo on the Web]]></title>
            <link>https://blog.cloudflare.com/cdnjs-the-fastest-javascript-repo-on-the-web/</link>
            <pubDate>Wed, 12 Dec 2012 18:35:00 GMT</pubDate>
            <description><![CDATA[ More than a year ago, Ryan Kirkman and Thomas Davis approached us about a project they were working on. Dubbed CDNJS, the project had a noble goal: make the world's Javascript resources load as fast as possible. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>More than a year ago, Ryan Kirkman and Thomas Davis approached us about a project they were working on. Dubbed <a href="http://www.cdnjs.com">CDNJS</a>, the project had a noble goal: make the world's Javascript resources load as fast as possible. They had been hosting the service on Amazon's CloudFront CDN, but as it got more popular the costs started to be significant. They approached us about whether we'd mind them using CloudFlare. We thought it was a great idea and we've been working together ever since. Today they just sent us data that shows CDNJS is the fastest Javascript repository on the Internet. More on that in a second, but first a bit about why CDNJS is so cool.</p>
    <div>
      <h3>Why Do You Need a CDN for Javascript</h3>
      <a href="#why-do-you-need-a-cdn-for-javascript">
        
      </a>
    </div>
    <p>The there are a core set of Javascript resources that are used across the web. Packages such as jQuery, Bootstrap, Backbone.js, and YUI underpin many of the web's pages. In order for these pages to load, the Javascript resources need to be downloaded. As a result, it makes sense for the resources to be on the fastest connections possible. However, that's only half the story.</p><p>The other benefit involves browser caching. If two sites use jQuery, ideally your browser only needs to download it once and then use the same code across both sites. In order to take advantage of this browser caching, both sites need to reference the same code via the same URL. As a result, it not only makes sense to reference a CDN for your Javascript code, but for you to use the same CDN as other sites are also using.</p>
    <div>
      <h3>The Big Boys</h3>
      <a href="#the-big-boys">
        
      </a>
    </div>
    <p>Google and Microsoft have understood the benefits of having a central repository of Javascript resources and both provide their own public repositories. The challenge is that they only have a limited number of the most popular resources. Moreover, since running the repos isn't their primary job, they are slow to update as new versions of code comes out.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6uFH4PdDIZcCafMQXaM1BJ/13cedd8cfaa30d19220e67e7c5910aaa/cdnjs_library.png.scaled500.png" />
            
            </figure><p>Everything so far is what Ryan and Thomas from CDNJS explained to us. They wanted to build a central repository for Javascript that was fast and reliable. They wanted to make sure it contained a wide range of the web's Javascript resources. They wanted to ensure that the latest versions would always be available. And they wanted to provide it to the web for free. We thought that sounded great, so we took over the job of serving the CDNJS resources from CloudFlare's <a href="http://www.cloudflare.com/network-map">global network</a>.</p>
    <div>
      <h3>Fast Wins</h3>
      <a href="#fast-wins">
        
      </a>
    </div>
    <p>Today Ryan and Thomas sent us the latest data on the performance of CDNJS versus the Google and Microsoft Javascript CDNs. The results are terrific. Graphs are at the top of this post, but the here's the data: on average, CDNJS is 50% faster than the Google's Javascript CDN (100ms vs. 157ms), and more than four times as fast as Microsoft's CDN (100ms vs. 432ms). That's based on data gathered using Pingdom to download the same Javascript resource (jQuery 1.8.3 minified) from the three CDNs from multiple points around the globe over the last week.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7jE7ME98gsICNjRLUEtpea/18e614dbfbc0b4698fa490b8524610a2/bootstrap_full_package.png.scaled500.png" />
            
            </figure><p>CDNJS is also expanding beyond just Javascript. They've recently added CSS and Images for popular packages like Bootstrap. In other words, you can load the entire Bootstrap package directly from CDNJS, saving you bandwidth and ensuring it is delivered as quickly as possible. What's also great is that since CloudFlare's network supports SSL, SPDY, and IPv6 by default, these benefits also extend to CDNJS. In other words, if you're using any Javascript resources on your websites it's a no-brainer that you should be loading them from the <a href="http://www.cdnjs.com">CDNJS network</a>.</p> ]]></content:encoded>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[CDNJS]]></category>
            <guid isPermaLink="false">3f6DRL3O2KdfnD98uicV0N</guid>
            <dc:creator>Matthew Prince</dc:creator>
        </item>
        <item>
            <title><![CDATA[App a Day #13 - CDNJS Selections for Legacy Browser Support]]></title>
            <link>https://blog.cloudflare.com/app-a-day-13-cdnjs-selections-for-legacy-brow/</link>
            <pubDate>Thu, 16 Jun 2011 23:14:00 GMT</pubDate>
            <description><![CDATA[ To demonstrate the utility of this open-source repository, today's CloudFlare App is CDNJS Selections, where a click installs the selected JavaScript libraries on your site. ]]></description>
            <content:encoded><![CDATA[ 
    <div>
      <h3>CDNJS Selections</h3>
      <a href="#cdnjs-selections">
        
      </a>
    </div>
    <p>CDNJS Selections is a few carefully selected scripts from the <a href="http://cdnjs.com">full CDNJS collection</a>, which is now <a href="/cdnjs-community-moderated-javascript-librarie">hosted on CloudFlare's global CDN</a>.</p><p>To demonstrate the utility of this open-source repository, today's <a href="https://www.cloudflare.com/apps">CloudFlare App</a> is <a href="https://www.cloudflare.com/apps/cdnjs">CDNJS Selections</a>, where a click installs the selected JavaScript libraries on your site.</p>
    <div>
      <h3>Five Easy Pieces</h3>
      <a href="#five-easy-pieces">
        
      </a>
    </div>
    <p>CDNJS has a wide range of community-driven projects in its peer-reviewed, open source repository. We're highlighting five which make the challenge of legacy browsers less frustrating for site owners.</p><ul><li><p>Modernizr</p></li><li><p>Google Chrome Frame</p></li><li><p>Flexie</p></li><li><p>CSS3 Finalize</p></li><li><p>JSON2</p></li></ul><p>Add any or all of these free scripts to your site with the <a href="https://www.cloudflare.com/apps/cdnjs">CDNJS Selections</a> App, without making a code change.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Apps]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[CDNJS]]></category>
            <guid isPermaLink="false">2diufYhLkt8lfJE6j5CEfW</guid>
            <dc:creator>John Roberts</dc:creator>
        </item>
        <item>
            <title><![CDATA[CDNJS: Community Moderated Javascript Libraries + CloudFlare]]></title>
            <link>https://blog.cloudflare.com/cdnjs-community-moderated-javascript-librarie/</link>
            <pubDate>Thu, 16 Jun 2011 20:43:00 GMT</pubDate>
            <description><![CDATA[ If you're using a Javascript library, the ideal case is that your visitors arrive on your site with it already stored in their browser's cache. The more sites that use the same URL to reference the library, the more likely it is that it will be cached even for first-time visitors.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>If you're using a Javascript library, the ideal case is that your visitors arrive on your site with it already stored in their browser's cache. The more sites that use the same URL to reference the library, the more likely it is that it will be cached even for first-time visitors. Google realized the importance of this for some of the major Internet libraries when they created the <a href="http://code.google.com/apis/libraries/devguide.html">Google Libraries API</a>. Unfortunately, Google has limited the number of libraries to 11 and not given much guidance on the practice of updating existing libraries oradding new ones.</p><p>In early 2011, Ryan Kirkman and Thomas Davis recognized that there were a number of additional libraries that needed the benefit of a central repository any site could link to in order to get the shared caching benefit. They created <a href="http://www.cdnjs.com/">CDNJS</a>, a project that allowed anyone to add new javascript libraries that would then get moderated by the project's community. They needed to make the libraries globally accessible on a fast network, so they looked to popular CDNs. They originally chose Amazon's CloudFront service, but as CDNJS gained in popularity the price became prohibitive for the non-profit project. Amazon's service also didn't offer an easy way to implement SSL/HTTPS connections, which limited CDNJS to only those sites that weren't using encryption. Not ideal on either front.</p><p>A couple months ago I saw a Tweet from Paul Irish, one of the creators of jQuery who is on Google's Chrome dev team, who was talking about how CDNJS needed to find a long term solution to ensuring a fast, reliable, affordable network. I reached out to Paul and Ryan via Twitter and put them in touch with Chris Joel from our team. Immediately the benefits were obvious: CloudFlare could offer CDNJS a globally-distributed network with extremely low latency that could support SSL/HTTPS. In doing so, CloudFlare could further our mission of making the web a faster, more secure place.</p><p>Yesterday the system went live and all the CDNJS libraries are now powered by CloudFlare. You can use CDNJS without signing up for CloudFlare for your own site. Existing CDNJS URLs will continue to work but should be updated to the latest URLs for full SSL support. CDNJS's community retains full control over what libraries are included. As they moderate in new libraries, or updates to existing libraries, they will be automatically included on our network and available worldwide at lightening speeds. We've ensured that all the HTTP headers are set in order for visitors' browsers to cache the libraries for as long as possible. As a result, the more people who use CDNJS as the central repo for their javascript libraries, the more everyone using it will benefit.</p><p>Our network rocks for this application. In the comparisons we ran with the old setup versus the CloudFlare new setup, our latency times were about 1/3rd of what CDNJS was previously seeing. We even compare extremely well versus the Google Libraries API. Don't take our word for it, try it yourself! Run the following commands from your terminal window:</p><ul><li><p>ping ajax.googleapis.com</p></li><li><p>ping cdnjs.cloudflare.com</p></li></ul><p>Your results may vary, but here's what I'm seeing from a major DSL provider's network in San Francisco:</p><ul><li><p>Google Libraries API Average Latency: 82ms</p></li><li><p>CloudFlare-Powered CDNJS Average Latency: 14ms</p></li></ul><p>At CloudFlare, we believe that open source, community-driven projects like CDNJS are the tools upon which the future of the Internet will be built. CloudFlare is proud to provide the global CDN infrastructure that helps power that future.</p> ]]></content:encoded>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Community]]></category>
            <category><![CDATA[CDNJS]]></category>
            <guid isPermaLink="false">eYXjfIWP85IiKg4GG9Tbz</guid>
            <dc:creator>Matthew Prince</dc:creator>
        </item>
    </channel>
</rss>