How I hacked the Bower Registry and what I learned from it  

Bower is a front-end package manager created at Twitter. It has about 20k active users and solves a real problem: Front-end package management. Two weeks ago, I stumbled upon a huge security risk allowing me to manipulate the underlying database and execute malicious code. In this post I’m going to explain the vulnerability I discovered.

Why it was vulnerable #

The way Bower validates a package is by checking if the corresponding Git repo actually exists. Since Git has a command for that, they decided to use git ls-remote [repo]. This isn’t such a bad idea, the problem was the way it was implemented in lib/validURL.js:

module.exports = function(url, cb) {
    var exec = require('child_process').exec;

    exec('git ls-remote ' +  url).on('exit', function(exitCode) {
        cb(exitCode === 0);
    });
};

The usage of exec in Node.JS is a HUGE security risk! Oftentimes, it can be easily exploited by manipulating the passed in string, just like in a plain, old SQL injection. In this specific case, this meant that any package could be inserted. Even worse, malicious code could also be executed. What this code did, was it essentially provided a REST-like interface for a remote shell.

It was dumb code.

Screen Shot 2014-08-19 at 1.49.35 PM.png

Within a few minutes after realizing this was real, I came up with a simple Proof of Concept using curl:

curl http://bower.herokuapp.com/packages -v -F 'name=proofofconcept' -F 'url=git://github.com/jquery/jquery.git; touch "alexanderGugel-sorry-proof-of-concept"'

This would create a new file called alexanderGugel-sorry-proof-of-concept (but could execute ANYTHING). The only thing that really mattered was the exit code (which was successful since touch was the last command). Therefore, the “package” has been inserted properly into the underlying PostgreSQL database.

After realizing that this was a huge security risk, I filed an issue on GitHub (which was a huge mistake, see below):

Screen Shot 2014-08-19 at 1.47.27 PM.png

What I learned #

  1. Never open a public GitHub issue for a serious security vulnerability.

    This seems so obvious, but I greatly underestimated the popularity of the issues containing the words “serious”, “vulnerability”, and “risk”. I still feel bad for doing this. Thankfully, no one compromised the DB.

    Screen Shot 2014-08-19 at 1.49.57 PM.png

    I even felt so bad that I manually reached out to sheerun and apologized. This was a huge mistake. Bad things could have happened.

  2. Heroku is great.

    Heroku has taken some additional security measures to prevent malicious users from manipulating the underlying file system. While this didn’t prevent me from temporarily creating a file on the server or running a script having DB access, this is a extraordinary useful feature that adds an additional layer of security to your app.

    If you want to read more about this topic, it’s called ephemeral filesystem:

    Each dyno gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the dyno’s lifetime its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other dyno and any files written will be discarded the moment the dyno is stopped or restarted.

  3. Because something has been developed by Twitter doesn’t mean it’s secure.

    While Bower is primarily being maintained by the community, the Twitter brand is still closely connected to it. Twitter put a lot of effort into releasing their internal projects as open source software on GitHub.

 
19
Kudos
 
19
Kudos

Now read this

Array.prototype.push

I’m always amazed by the excellent readability of V8’s source code. I think everyone should have a rough idea about where to look for specific implementation details of the most common JavaScript functions. As an example, let’s look at... Continue →