audit your gems

Gems don’t have to be trustworthy:


Can you find a way to inspect the gem without installing it? Somehow the file doesn’t appear in the project list. And gem unpack wants it installed first. Would the unpacked version even tell you anything?

What if I had slipped this into cgi_multipart_eof_fix, one of the most-downloaded gems? What if someone had compromised my Rubyforge account, and they did it?

Audit your gems. Update specific gems when you need new features, and avoid sudo gem update. Gems and Rubyforge are a great convenience. But know who you’re trusting.

8 responses

  1. Good point… I noticed the fact you can make gems ‘disappear’ from everywhere but the gem source cache recently too.

    Short of having gems installed in a sandboxed environment on a trial before a real install… I think signing gems could at least help with the issue of a normally trusted source becoming compromised…

    But the extra effort required by gem authors would make adoption low I expect :(

    This issue must be prevalent in most community based package managers?

  2. You can already sign gems, see here. The security policy business is convoluted for users, so they don’t pay attention to it, so they don’t require authors to use it. At least that’s my opinion. Plus it’s unclear how to specify a required policy level in ~/.gemrc or similar.

    Most system package managers require you to trust the source. For instance, with APT, you have to add new sources to the /etc/apt/sources.list file. Otherwise you just get Debian or Ubuntu’s default sources, and those are closed to public submissions. Theoretically they could be poisoned or hacked, though. I don’t know if APT packages are signed or not.

    I don’t know how CPAN works, but I assume it has the same issues as Rubygems. I think Python Eggs might be more decentralized.

  3. One significant problem is the the need for root access when running gem (i.e. sudo).

    On my single user dev box, I just keep all the gems in ~/gems. I own all them so I can install gems with my own privs, not the root user’s.

    $ gem install foo
    => installs foo into ~/gems

    On a server, perhaps the gems could be owned by the server process (e.g. www, apache, etc.).

    Even if gems are malicious, at least they aren’t running with root privileges.

  4. There are so many ways to crack the system at all levels (from Rubyforge, passing through the mirror network up to gem install) it’s not even funny. :(

    As for installing as non-root: from the moment you install a gem in some environment and have to work in said env. (for instance, to run unit tests during development), you’re screwed. On a devel. box, I don’t care about root; if my data is tainted and I have to review it from a clean env, game over (reinstalling the OS is less of a problem than rebuilding my development env).

    Is this any worse than the situation with tarballs? Yes and no. RubyGems introduces several easily exploitable targets, and even though it’s possible to use it safely, it’s such a PITA (arguably harder than with a plain tarball) that you’ll often just cross your fingers and hope. I bet few people review the metadata & extension scripts before installing and proceeding to review the code itself (or better yet unpacking manually, which doesn’t leave you open to e.g. rdoc exploits).

    When you gem install, you’re not only trusting Rubyforge but also N mirrors. Crack one and you screw some % of the people installing Rails (and they’ll most probably never know).

    In the past, gems have been overwritten at Rubyforge’s level without even trying. The script running on Rubyforge’s server that copies gems to the index hasn’t really been publicly reviewed…

    Nobody is signing his gems. You can download manually from and verify the hexdigest… but there’s in general nothing to check against, you can at most see if the file looks the same in most mirrors.

    To sum up, in practice RubyGems doesn’t help with the problems you’d have with plain old tarballs (trusting the original source, making sure we’re getting the same file) and creates potential for a number of attacks that would prove very profitable thanks to the sudo gem update culture.

  5. Yeah. If you install gems in the environment where you use them, your data is at risk. sudo just makes damage control a bit harder from a technical standpoint.

    There doesn’t seem to be a single signed gem in existence:

    curl -s | \
    grep signing_key | sort | uniq



    No keys; not even mongrel.

  6. I can definitely see how this is a problem, especially as adoption of Ruby increases, however, as the manual for signing gems points out, there’s not a whole lot in the way of infrastructure in place for doing anything beyond self-signed certificates. I’m not sure that that is actually “better than nothing.” I have no problem at all with taking the time to sign my gems, but I suspect it wouldn’t do much good. Especially since the default policy doesn’t care whether a gem is signed or not.

    And auditing gems manually is not really all that viable. I’m not going to sit down and verify that someone hasn’t snuck something into the 75,000 some lines of code in Rails every time a new version of Rails comes out and realistically neither is anyone else.

    I’ve long been of the opinion that having gems installed as root can be a problem. If nothing else, it’s a major pain on shared servers. Not as big a deal for me now that I’m running on a VPS setup for my hosting needs, but certainly it has been a hassle in the past.

    Personally, I try to stick everything I can into a vendor directory, but that only goes so far, especially if native extensions have to be built.

  7. Regarding apt: The repository indexes are signed and contain digests of the individual package files. See the apt-secure(8) man page (on Debian) for more information.