The silent guardian: why bundler checksums are a game-changer for your applications

The Silent Guardian: Why Bundler Checksums Are a Game-Changer for Your Applications

Introduction: A Fragile Trust

The Ruby ecosystem relies heavily on RubyGems.org as the central platform for distributing and managing gems. We all depend on it to provide reliable, untampered gems that are the foundation for our projects. This trust in the system is a cornerstone of Ruby and Rails software development and undoubtedly part of what makes it so successful.

In 2022, two critical incidents involving RubyGems’ backend highlighted cracks in this trust. Although no damage occurred, the event raised concerns about the potential for malicious actors to replace widely used gems, like Rails, with compromised versions.

These incidents once again emphasized the need for additional safeguards to verify the integrity of gems and ensure they remain unchanged from their original state. Bundler 2.6 addresses this challenge with built-in checksum verification.

Sponsored

This article examines how checksum verification works, its benefits to gem users and maintainers, and practical steps for enabling it. I also present how this feature mitigates risks and helps protect the software supply chain from tampering and other attacks.

The Anatomy of a Supply Chain Attack

A supply chain attack targets the systems and processes that developers depend on to build, test, and deploy software. Instead of attacking an application directly, an attacker compromises a trusted dependency or service, allowing malicious code to propagate through the software lifecycle. These attacks can be subtle, difficult to detect, and highly impactful.

What Happened with RubyGems?

In 2022, RubyGems experienced two critical vulnerabilities (CVE-2022-29176 and CVE-2022-29218 ) in its gems storing backend. If attackers would poison a cached version of a popular gem, such as Rails or Devise, with a compromised version, the impact could have been severe.

Just imagine an attacker inserting a backdoor into a specific version of Ruby on Rails you are currently using. Scary, right?

*Example of a cache poisoning attack flow where attackers inject malicious packages into RubyGems’ CDN, bypassing security controls.

Why Are These Attacks So Dangerous?

  1. Widespread Reach: Popular gems are used by tens of thousands of developers and organizations, meaning a single compromised gem can affect many applications.

  2. Stealth: In some cases, tampered gems could retain the same version number and metadata, making it difficult to detect the changes without specific verification processes.

  3. Trusted Ecosystem: Developers often trust dependency management systems to provide safe and unaltered packages, making it easy for attackers to exploit this trust.

Checksums as a Defense Mechanism

Checksum verification provides a critical safeguard against certain types of supply chain attacks by ensuring that gems remain unchanged from the time they are first recorded in the Gemfile.lock. The recorded checksum is a cryptographic fingerprint, uniquely identifying the gem’s exact state. If a gem file is replaced or tampered with, the checksum will no longer match, and Bundler will block its installation.

While this mechanism does not protect against scenarios where an attacker releases new versions of a gem with malicious payloads due to owner account takeover or publishes entirely new, malicious gems, it is highly effective in preventing the replacement of existing versions. This includes defending against attacks where legitimate gem versions are swapped out for compromised ones on gem servers or during transit.

This feature offers developers a reliable and automated way to trust their known dependencies. It significantly reduces the risk of unnoticed tampering and strengthens the overall security of the RubyGems ecosystem.

See also  Securing Ubuntu: Best Practices for Keeping Your System Safe

Enter Bundler 2.6: The Silent Guardian

For years, the Ruby community has needed a reliable way to ensure the integrity of gems – not just at the moment of download but throughout their whole projects lifecycle. Bundler 2.6 addresses this with checksum verification, providing a simple yet powerful solution. I believe it is one of the most critical security features introduced in recent years.

What is Checksum Verification?

Checksum verification ensures that the gems you install are identical to the ones originally recorded in your Gemfile.lock. When you enable this feature, Bundler calculates a cryptographic hash (sha256 checksum) for each gem and stores it in the lockfile under a CHECKSUMS section. Each time Bundler installs a gem, it recalculates the checksum and compares it to the stored value. If the checksums do not match, the gem is flagged as tampered, and installation is blocked.

This approach effectively protects against replacement attacks, where an attacker swaps a legitimate code with a malicious version. The checksum is a fingerprint, making even the smallest unauthorized changes detectable.

*Example of Bundler 2.6’s checksum verification process, ensuring gem integrity by verifying SHA256 checksums before installation.

Key Features of Bundler 2.6’s Checksum Verification

  • Automatic Validation: Bundler seamlessly checks gem integrity during installation without additional configuration after the initial setup.
  • Protection for All Gems: This feature works for every non-local gem listed in the Gemfile.lock, including dependencies fetched from RubyGems.org, private gem servers, and internal registries.
  • Backward Compatibility: Bundler only enforces checksum verification if the Gemfile.lock includes the CHECKSUMS section, ensuring a smooth transition for existing projects.

Below you can find an example of the CHECKSUMS Gemfile.lock section:

CHECKSUMS
  actioncable (7.2.1) sha256=b409c96b0acc90abe6aa8fd9656eaff0980c1b36c9e22b8f7c490a46eafc2204
  actionmailbox (7.2.1) sha256=09c20d0bcb769a6521d22cb8987e2d1d8335b58610957a6c615c85e6743adf89
  actionmailer (7.2.1) sha256=e4853a32c84105066e64d900ee1025ef075893ee3c51de3a3bc59a6e09586e56
  actionpack (7.2.1) sha256=260b80acc720123f23eb2b106b04d2de7d8cf0492d4eeb2dfa7afc8be36dcaad
  actiontext (7.2.1) sha256=1257a2384373188039fc35d46946e757014710361a4af4481e37b510ac7d7d79
  actionview (7.2.1) sha256=d1f8f4df2bff842a03e2a6e86275e4d73e70c654159617ad4abbe7c6b2aed4f4
  activejob (7.2.1) sha256=eb145f5aaf8276f37b9e4e9f72f3d56b1733172b4be680e836c765f2e6a3c503
  activemodel (7.2.1) sha256=7b24e3927122b99c4623f07607a1d0f1cfd598f9dc5077e70178536dd6663348
  activerecord (7.2.1) sha256=b58a26b9337594f2639cafcc443f4d28d786289f5b5b07b810e8251eeace533c
  activestorage (7.2.1) sha256=e5d6746aa9e5d92fff9d214fad782b6a7189bc080d319c0b196e3dfa1595a676
  activesupport (7.2.1) sha256=7557fa077a592a4f36f7ddacf4d9d71c34aff69ed20236b8a61c22d567da8c24
  base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
  bigdecimal (3.1.8) sha256=a89467ed5a44f8ae01824af49cbc575871fa078332e8f77ea425725c1ffe27be
  builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
  concurrent-ruby (1.3.4) sha256=d4aa926339b0a86b5b5054a0a8c580163e6f5dcbdfd0f4bb916b1a2570731c32
  connection_pool (2.4.1) sha256=0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4
  crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
  date (3.3.4) sha256=971f2cb66b945bcbea4ddd9c7908c9400b31a71bc316833cb42fa584b59d3291
  diff-lcs (1.5.1) sha256=273223dfb40685548436d32b4733aa67351769c7dea621da7d9dd4813e63ddfe

Why It Matters

Checksum verification addresses one of the most significant threats in software supply chains: tampering with existing packages. It ensures that the gems you install have not been altered since their original recording, protecting against attacks that could compromise your application.

However, it is essential to note what checksum verification does not cover. It cannot prevent attackers from publishing malicious new versions of gems or creating entirely new gems with harmful payloads. Instead, its strength lies in safeguarding against replacement attacks, preserving the integrity of your existing dependencies chain.

A Seamless Integration

One of the best aspects of this feature is how unobtrusive it is. After enabling it, it operates silently in the background, providing an additional layer of security without requiring any manual work.

Security Benefits: A Two-Way Shield

It provides security advantages for gem users and developers as it acts as a two-way shield, protecting those who depend on gems from tampered artifacts and giving gem maintainers a reliable way to establish trust with their users.

For Gem Users: Ensuring Dependency Integrity

Checksum verification is a vital safeguard for developers and organizations. It ensures that every gem installed matches the original version recorded in the Gemfile.lock. This protection offers several benefits:

  • Defense Against Tampering: Prevents unauthorized alterations to gem files, whether they occur during transit or on compromised gem servers.
  • Automated Protection: Bundler handles checksum verification automatically during installation, reducing the risk of human error.
  • Peace of Mind: Developers can trust that the gems in their projects are identical to the versions they intended to use without needing additional verification scripts or processes.

For Gem Distributors: Building and Maintaining Trust

Gem developers offering private packages, such as Sidekiq Pro/Enterprise, Karafka Pro, Avo, and others, can now breathe easier. Previously, they faced concerns about potential compromises to their private gem servers, which could lead to tampered gems reaching their users unnoticed.

To mitigate this, I, for example, recommended manual checksum verification as an additional layer of protection. However, this approach had its limitations – it was typically integrated into CI/CD pipelines rather than being enforced directly at the point of gem installation. This meant that verification wasn’t fully “shifted left,” leaving room for vulnerabilities during the initial fetch or local usage.

With this release of Bundler, such manual processes are no longer necessary. The verification happens automatically for every gem that is being installed. This not only simplifies workflows for users but also provides gem providers with confidence that their packages remain untampered from distribution to installation.

See also  Life at Canonical: Victoria Antipova’s perspective as a new joiner in Product Marketing

By eliminating the need for custom scripts and CI/CD-dependent checks, Bundler makes security a seamless and integral part of the dependency management process. This transforms how private gem providers secure their offerings and maintain trust with their users.

A Stronger Supply Chain

The dual benefits of checksum verification – protecting gem users and maintainers – make it a critical component of a secure software supply chain. While it doesn’t prevent the publication of new malicious gems or harmful updates, it creates a reliable mechanism to ensure existing gems remain unaltered.

This two-way protection builds confidence for both sides of the gem ecosystem, fostering trust and encouraging secure practices across the board.

Enabling Checksums: Securing Your Pipeline

Enabling checksum verification is a straightforward. With just a few steps, you can ensure that every gem you install is verified for integrity, protecting your pipeline from tampered or compromised packages.

  1. Update to Bundler 2.6+

Checksum verification is only available in Bundler 2.6 or newer. Begin by updating Bundler to the latest version:

Sponsored
gem install bundler

Verify the installed version to ensure the update was successful:

bundler -v
  1. Add Checksums to the Lockfile

Once you’ve updated to Bundler 2.6, you need to enable checksum verification in your Gemfile.lock:

bundle lock --add-checksums

This command generates a CHECKSUMS section in your Gemfile.lock, recording the cryptographic hash of every gem currently listed. These hashes will be used for verification during installation.

  1. Enable Checksum Verification for Future Lockfiles

To ensure that all new projects and lockfiles include checksum verification, configure Bundler to always add checksums:

bundle config lockfile_checksums true

This setting ensures that checksums are included automatically whenever you create or update a lockfile.

  1. Normalize Your Lockfile (If Necessary)

In some cases, your Gemfile.lock might not include platform-specific variants of your gems, especially if the PLATFORMS section only specifies ruby. For instance, your lockfile may list nokogiri-1.18.0, while Bundler installs a platform-specific variant, such as nokogiri-1.18.0-x86_64-linux, depending on your environment.

This discrepancy can cause issues with checksum verification because the checksum recorded in the lockfile applies to the generic variant, not the specific one being installed. To address this, Bundler 2.6 will print a warning when it detects a mismatch and recommend normalizing your lockfile.

To normalize your lockfile and ensure all platform-specific variants are included, run:

bundle lock --normalize-platforms

This command updates the Gemfile.lock to include platform-specific variants of your gems. Once normalized, checksum verification will work correctly for all variants, providing full integrity checks regardless of the environment.

When Things Go Wrong: Handling Mismatched Checksums

But what happens when a mismatch occurs? A mismatched checksum indicates that the gem being installed does not match the one recorded in your Gemfile.lock. This section explains common reasons for checksum mismatches, how to troubleshoot them, and what actions to take.

What Causes Checksum Mismatches?

  1. Tampering or Compromise: The gem may have been altered maliciously, either on the gem server or during transit.
  2. Repackaging by the Gem Distributor: Some distributors may unintentionally repackage gems without updating the checksum.
  3. Corrupt Download: Network issues or disk errors can lead to incomplete or corrupted gem files.
  4. Manual Lockfile Changes: If someone manually edits the Gemfile.lock, it could lead to inconsistencies between the lockfile and the actual gem.

How to Identify the Issue

When a checksum mismatch occurs, Bundler will halt the installation process and provide an error message similar to this:

Bundler found mismatched checksums. This is a potential security risk.
  gem_name (version) sha256=expected_checksum
    from the lockfile CHECKSUMS at Gemfile.lock:line_number
    and the API at gem_source_url

This message highlights:

  • The gem and version affected.
  • The expected checksum (from Gemfile.lock) and the actual checksum (from the downloaded gem).
  • The source of the gem.
See also  Step-by-Step Ubuntu Installation Guide

Steps to Troubleshoot and Resolve

  1. Verify the Source: Check the gem source URL. Ensure it is the correct and expected repository or registry.
  2. Compare Checksums:
    • Extract the checksum from your Gemfile.lock:
 grep -A 1 "gem_name" Gemfile.lock | grep sha256
  • Calculate the checksum of the downloaded gem manually:
 sha256sum path_to_gem.gem
  • Compare the two values to confirm if tampering or repackaging occurred.
  1. Check for Updates: Verify whether the gem maintainer has released a new version or repackaged the gem. In such cases, update your Gemfile.lock using:

    bundle update gem_name
  2. Consult the Maintainer: If the issue persists, contact the gem maintainer to confirm the integrity of the gem and its checksum.

  3. Investigate Tampering: If tampering is suspected, avoid using the gem until the source of the issue is resolved. Report the issue to the relevant parties, such as the gem maintainer or us at RubyGems.org.

When in Doubt, Investigate

Checksum mismatches are not always a sign of malicious activity but should never be ignored.

BY NO MEANS do not blindly update/disable the checksum verification when a mismatch occurs.

Each such incident should be thoughtfully investigated!

Why Private Registries Need Checksums

Private registries often host proprietary or sensitive gems. Without checksum verification, these gems are just as vulnerable to tampering or accidental corruption as public ones. Common risks include:

  • Internal Threats: Unauthorized modifications by users with access to the registry.
  • Compromised Distribution Channels: Man-in-the-middle attacks or compromised networks during gem transmission.
  • Human Error: Repackaging or updating gems without properly communicating changes to users.

Checksum verification addresses these issues by ensuring that gems downloaded from private registries match their original state as recorded in the Gemfile.lock.

A Safer Ecosystem: Checksums for Everyone

In my opinion this is more than a feature – it’s a step toward a more secure and trustworthy Ruby ecosystem. By protecting both individual projects and the broader software supply chain, checksums benefit everyone involved in developing and distributing Ruby gems. Whether you’re a gem user, maintainer, or private registry provider, adopting this practice strengthens the ecosystem as a whole.

Security is a shared responsibility across the Ruby community. Everyone – developers, maintainers, and organizations – contribute to a safer ecosystem when adopting checksum verification. This collective effort not only protects individual projects but also raises the standard for security in the Ruby community as a whole.

Conclusion: The Unseen Hero of Your Codebase

In an era where supply chain attacks are becoming increasingly sophisticated, checksum verification provides another line of defense for the Ruby ecosystem. It operates silently in the background, requiring minimal setup while offering significant security benefits. It protects developers from tampered dependencies, helps maintainers preserve trust in their gems, and gives organizations confidence in their supply chains. Since it works with private registries, it ensures that both public and proprietary gems benefit from the same level of integrity.

While it cannot prevent malicious new gem versions or entirely new harmful gems, it is a powerful safeguard against replacement attacks, one of the most insidious threats to the software supply chain.

This Bundler release may not be flashy, but its impact is profound. Authors and all the contributors to this feature are the unseen heros of your codebase, quietly protecting your dependencies so you can focus on what matters most: building great software. Now is the time to upgrade to Bundler 2.6, enable checksums, and take a crucial step toward a more secure future for Ruby development.

Acknowledgments

This feature represents not only a significant technical achievement but also the dedication and teamwork of several contributors.

The journey began with a contribution by GitHub user @kuahyeow in PR #5808, laying the foundation for this critical feature. Later, @mercedesb continued the work in PR #6374, building upon the initial implementation.

Subsequently, @seggidins and @martinmde took over, refining and completing the feature with valuable input and reviews. Martin also prepared an RFC that helped shape the final implementation.

Finally, the work of smoothing out the feature, preparing it for release, and developing a gradual opt-in rollout plan was undertaken by @deivid-rodriguez.

To everyone involved – thank you for your hard work, dedication, and commitment to enhancing the security and trustworthiness of the Ruby ecosystem!

The post The Silent Guardian: Why Bundler Checksums Are a Game-Changer for Your Applications appeared first on Closer to Code.


Discover more from Ubuntu-Server.com

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

    Leave a Reply