Of Course I’ll Let You Execute Arbitrary Javascript Code in My Users’ Browsers

Kevin J. Dolan
Metric Tech
Published in
8 min readJul 14, 2016

--

I did my fair share of contract work before I was CTO of Metric Collective, and I can’t tell you how many times I got the request to add a new JS snippet that would change the world. Even when I moved out of the contract world and into full-time development, I continued to get these requests from management. At the time, I didn’t really think much of it; it seemed commonplace.

My first eye-opener on the subject was one of the first JIRAs I was assigned interning at NextJump. The JIRA was trivial: here’s an Optimize.ly snippet, paste it into the base template. It was easy to add the snippet, I was able to test it out, and it magically worked. I submitted a patch and sent it to QA for approval. I swiftly received this AIM message:

“Hell no.” — Ominous QA man I never met.

I was baffled, since I did exactly as I was told. He carefully explained the risks of my patch to me:

  • You essentially give up full control over the content of your web page to some unvetted third party. Because Javascript can perform arbitrary manipulations (the thing Optimize.ly is literally designed to do), it’s not your webpage anymore.
  • You give full visibility over interactions with your web page to that third party, and possibly others they invite in. This might be as simple as logging that the page view occurred, or as malicious as copying down credit card numbers and sending them over the wire. This includes credential cookies.
  • Speaking of credential cookies, if you have an internal admin on the same domain as the snippet, you could leak admin-level credentials to third parties. If they were so inclined, this would be a good vector for hijacking your website. If you use a popular CMS like Wordpress, guess what that means?
  • Even if you work hard to vet the contents of the injected code as it is written (which is near-impossible, since it is usually highly obfuscated), most of these snippets are served up from foreign origins, so they can simply swap out the Javascript contents from under you. They could even do that for a subset of users, or avoid hijacking traffic that comes from your own geographic region to avoid detection.
  • Even resources that don’t execute code (like images) will leak information about the page referrer, allowing for tracking of users across websites that may be undesirable.
  • A lot of times, these snippets are delivered over a CDN, but piling more and more requests up on the wire doesn’t do great things for your site’s performance.

Despite all these problems, the situation today has become far, far worse. The rise of glue developers and out-of-the-box JS solutions has led to commonplace acceptance of the practice of injecting JS with very little forethought for security.

Do you really trust a one-year-old, four-person startup in Denver with full control over your website? Even if you do trust them, how sure are you that their infrastructure is impervious to subversion?

Protecting against malicious users from injecting Javascript onto our pages has come along way since the hey-day of XSS attacks in the late 2000’s, and yet we are sitting at our desks, intentionally allowing third parties full control of our webpages.

Why aren’t more people screaming about this gigantic hole?!

Thankfully, our resident security expert Adrien was only able to point to one major precedent for this being used as an attack vector: the case of Hackers from China hijacking a Baidu analytics tag to DDOS Github. By subverting the insecure HTTP delivery of the script tag through a DNS flaw, they were able to conscript 1% of all users downloading the script into a massive DDOS army. Baidu likely had nothing to do with the attack, but some external party was able to leverage their massive distribution to their own nefarious ends.

I wonder how many cases of this were less severe and went unnoticed. If anybody knows of any other cases of this leading to an attack, I’d love to hear about it. Please email me.

I’ll admit it, I used this vector for some grey-hat purposes back in my college days. In college, I wrote a terrible Javascript animation library that inexplicably became very popular among Spanish-speaking web developers. In order to facilitate onboarding, I offered the library over a public CDN that anybody could use.

At its peak, the script was being loaded from a few hundred websites and receiving about 100k loads per day. Some of my friends were in a band and they were participating in a local battle-of-the-bands competition for a radio station that featured weekly online votes to move to the next round. Their voting system did nothing to defend against XSRF attacks, but did limit votes to 1 per IP address.

So naturally, my friends won by a landslide of votes, most of which originated in Latin America.

It’s clear to see why this is the state we’re in. There are a handful of main categories of client-side JS injections popular these days, each providing a unique and compelling value prop:

Ad-Tech

The ROAS you can achieve using retargeting are compelling, and successfully running a retargeting campaign means you need to pipe information to some external third party about what people are doing on your site, not only at page-load time, but also as people use your website. Apart from retargeting, ad platforms that offer real-time bidding or intelligent optimizations can benefit from conversion data to learn about which audiences convert best.

As a publisher, delivering ads and tracking their performance can be a surprisingly sophisticated job. There are so many ad-tech tools that do something cool and integrate with other ad-tech tools in a myriad of (generally hacky) ways. By boiling the implementation task down to just “paste this snippet” during the sales pitch, it’s easy to move the process along.

Further, project management in the ad-tech space can be at times overwhelmingly dominated by business weenies, who don’t sufficiently understand the risks of the underlying technical decisions being made. Since it’s so easy to make a business case for these tools, and it’s relatively natural to package them as injectable JS, the sales process driving their adoption has been a home-run. Once it’s sold to the higher-ups, there’s not much a developer can do to kill the deal and everybody just hopes the economic arrangement is enough to incentivize the JS-injector to be well-behaved.

When we experimented with AdRoll on FranchiseHelp, we found that the inclusion of it alone contributed to the injection of resources from 12 distinct origins!!

Tracking tags

When building analytics tools, that data needs to get piped somewhere else so you can ask questions of it. Google Analytics has been massively successful at achieving reach. We found in an analysis of ProductHunt websites, GA was included on 84% of websites, giving Google an unparalleled view over the entire internet. Allegedly, Google doesn’t use this data for their own purposes, but come on…

At least I trust Google with my life already. Other, newer tools like Kissmetrics and Mixpanel have also been really successful; they offer a really compelling set of features, they’re fast and slick, but I know very little about who is behind these companies.

At Metric, we’re migrating away from turnkey solutions like these and running more of our own analytics software through the Metric Collector project.

Rich APIS

Sometimes the features an external JS library provides are rather sophisticated, involving rich sets of components and asynchronous data requests to external services. A great example of these are maps APIs, which have complex mechanisms in place for efficiently loading and rendering tiles.

Due to the amount of sophistication that would be required to get all of the different pieces in place, leveraging something more full-featured like a JS snippet, which can do essentially whatever it wants, is pretty useful.

JSON-P APIs also fall into this category, as they allow the injection of arbitrary JS as a means to bypass CORS policies. While the intended purpose is to deliver data, they can be as dangerous as any other type of JS injection.

External Embeds

The open web has been pretty great at finding ways to syndicate content. You can’t go far without finding an embedded YouTube video inline on your favorite websites. Embeds are used for all sorts of things, like data widgets, content promotion, and so on. Sometimes, these live in iframes and are safely isolated from the parent page, but so many people just use Javascript to do it.

We elected to use Javascript back when we were working on AddressReport to power our embeddable data widgets which were designed to enhance home listings across the internet using our data. We ultimately chose to do so for the purpose of flexibility, which I think is compelling to a lot of companies building embeds.

I expected to receive a lot of pushback about that decision, but not a single partner raised any objections whatsoever about security. When speaking with the team over at Breezometer, who offer a similarly packaged embed, they told me I was the first person to ever even mention the concern to them. I’m convinced most people are totally unaware of this risk!

Reusable Components

There are plenty of not-for-profit open-source projects out there with fully inspectable codebases you can dive into* and deliver safely from your own CDN. But there’s a growing trend in building out reusable components that are monetized by charging a licensing fee. An appealing way to monitor and enforce those licensing contracts is to deliver the components using JS snippets.

*But you probably won’t; hopefully somebody else will, right?

These have the advantage of simplicity (so easy for a manager to simply write, “paste this snippet” and call it a day). When I get these requests, I usually go into this whole spiel, but I’ll admit I occasionally acquiesce if I’m feeling particularly tired, only to regret it later when our webpages are slow.

What frustrates me about these is that the features they offer rarely justify hosting the Javascript externally. Though they may be bound to a licensing agreement, there’s no real benefit on our end in keeping them separate from our typical asset pipelines! Sometimes, the situation is so bad (calling you out HelloBar), that the main thing they offer can be reproduced with a few lines of HTML and CSS!

To find out just how prevalent the practice is, we analyzed nearly 7,000 websites featured on ProductHunt, and the results were terrifying.

With all this in mind, there’s definitely value in leveraging external JS, but the practice really needs to be reeled in before something serious goes down. For every noteworthy hack out there, there are thousands of subtler attacks that go unnoticed. I wouldn’t be surprised if there were some very popular compromised snippets out there, live right now, just piping credit cards to who-knows-where in volumes low enough to avoid detection.

Next time your boss asks you to “just paste this snippet,” send them this article.

Cool combination.

Metric Collective is a holding company based in NYC that both acquires existing companies and builds new ones from scratch, mostly focusing on tools that support the SMB space. If you enjoyed our shamelessly self-promoting dev blog and want to talk about opportunities at Metric, email me, or read more stuff by the business weenies at Metric Musings.

--

--