For the past 6 years, private Github repositories using Travis CI have been vulnerable to a privilege escalation attack. Under certain configurations, an attacker with read-only access to the Github repo could change the code just by submitting a pull request.

This was reported to the Travis CI security team and has been fixed.

Introduction

About two months ago Dane Powell, a co-worker in Professional Services, messaged me asking to help him verify that Travis CI was allowing him access to a private SSH key. I took a look at the build and confirmed there was a public and private key pair accessible when a build was running on the Travis CI container.

Looking into other repos and builds, it became apparent that SSH keys only existed on private Github repos. This made sense because Travis CI can simply clone a public repo over HTTP with no authorization required.

With this information an interesting attack began to form in my mind.

Github, Pull Requests, and Travis CI

Here is some background in case you aren’t already familiar with the continuous integration testing method of using Travis CI and pull requests.

Github is one of the most commonly used code storage services on the Internet. One of the features that helped it gain popularity is the concept of a pull request. A developer can create a project (public or private) and allow other developers access to the project's code. If another developer finds a problem or wants to add a new feature to the project, the only method of changing code is to submit a pull request. This asks the project owner to pull the new code changes from the other developer. Using this method, the project owner can carefully review any changes suggested and approve or deny them as needed.

On a private Github project, a developer must be given explicit access to the repo in order to access it. This access can come in the form of read-only or read/write. Unless the developer is working with the project owner to help maintain the project itself, the vast majority of the time developers are given read-only access. This allows the project owner to fully take advantage of the pull request workflow described above.

Travis CI is a continuous integration service which offers tight integration into Github, and allows project owners to have automated tests run against any proposed code changes when a pull request is created. This gives the code change a pass/fail rating and helps to reduce human error with things such as typos, and code formatting issues. It can even test the project's functionality.

“PR Disaster”

Once I knew the environment Travis CI created to review a pull request had access to the SSH keys needed to write to the Github repo, putting together an exploit was straightforward. (Developers will recognize that “PR Disaster” has a double meaning in this case: a public relations mess, yes, but also a “pull request” problem, since a pull request is the method of attack.)

The exploit required 3 things to be in place:

A private Github repo

The attacker is granted read access to the repo

Travis CI configured to run on pull requests

The key to this lays within the fact that the Travis CI configuration steps are stored within the repo itself. This means a pull request can not only suggest a code change to the project, but a change to what Travis CI actually does as well. Putting that together with the SSH keys meant a pull request can instruct the Travis CI container to write anything back to the Github repo on any branch. This completely bypasses the pull request workflow and the read-only access granted to the attacker.

Creating a pull request adding something like following to .travis.yml results in the master branch being changed.

before_script:

- git checkout master

- echo "# This is a direct change to README.md" >> README.md

- git add README.md

- git commit -m "Commit from TravisCI"

- git push origin master

This example simply adds extra text to the README.md file but obviously a malicious change, such as adding a backdoor in a php application, could be done instead.

The Fix

I sent Travis CI an email in late September describing the issue. The Travis CI security team quickly responded and began working on a fix.

Their ultimate fix was to batch update all existing keys to be read-only, and their integration was updated to create read-only keys for all new projects using a new method provided by Github that didn’t exist when the Travis CI was originally created. This is detailed on the Travis-CI blog.

The blog post makes a note stating the Travis CI team believes that it "is unlikely this vulnerability has been exploited." While I have no reason to doubt their judgment, I would recommend reviewing the commits to any Github projects you may have that fit these requirements. This is especially true if a project has a lot of developers with access.

Note: Acquia Cloud CD pipelines, Acquia’s tool for developing, testing, and deploying websites or other applications to Acquia Cloud, is not affected by this vulnerability. Acquia customers also have the option to request an Acquia Security Audit, which will ensure that your site has been architected, developed, and configured in line with best practices to protect against common attacks. Acquia examines your site to identify commonly exploited security holes. We compare your site to best practices, train you to close them, and validate they are fixed properly before they can be used against you.