SHA-256 shows up in more places in a Ruby on Rails stack than most developers realize, from the filenames of your compiled CSS to the Gemfile.lock that pins your dependencies. At Essence Solusoft, we dig into exactly where SHA-256 is used in Rails, where it isn’t (a common assumption that turns out to be wrong for the current default pipeline), and why it matters for caching and supply chain security.
We verified every claim below against the official Rails Guides and the actual source code of Sprockets, Propshaft, and Bundler, so you can treat this as a reference rather than a recap of blog-post folklore.
What “Asset Fingerprinting” Means in Rails
Asset fingerprinting is the technique of making a file’s name depend on its content. Rails generates a digest of a compiled asset’s bytes and appends it to the filename, so application.css becomes something like application-a1b2c3d4.css. When the file content changes, the digest changes, which forces browsers to fetch the new version instead of serving a stale cached copy. This is the basis of Rails’ long-expiry cache-busting strategy for assets.
That much is consistent across Rails’ asset pipeline implementations. What differs, and where a lot of write-ups get sloppy, is which hashing algorithm actually generates that digest, because Rails has shipped two different asset pipelines with two different defaults.
Sprockets: SHA-256 Is the Real Default
If your app predates Rails 8, or you’re still running Sprockets explicitly, SHA-256 is in fact the digest algorithm in play. Sprockets’ DigestUtils module defines Digest::SHA256 as its default digest class, and the top-level Sprockets configuration sets digest_class: Digest::SHA256 directly. The official Rails Guide for older Rails versions confirms this too, describing an SHA256 digest generated from the contents of compiled files during precompilation and inserted into the filename.
So for Sprockets-based apps, fingerprinted asset URLs like public/assets/rails-f90d8a84c707a8dc…png are literally SHA-256 hex digests of the file’s contents.
Propshaft (Rails 8 Default): It’s Actually SHA-1, Not SHA-256
Here’s the correction worth knowing if you’re on a current Rails 8 app. Propshaft, which became the default asset pipeline starting with Rails 8, does not use SHA-256 for filename fingerprinting. Looking at Propshaft’s Asset class directly, the digest is generated with Digest::SHA1.hexdigest(…) and then truncated to the first 8 characters.
So if you’re building on Rails 8 with Propshaft (the default for new apps, since Sprockets is opt-in at that point), your fingerprinted filenames are short SHA-1 digests, not SHA-256. If your team assumed otherwise, that’s a reasonable assumption to make given how consistently “SHA256” gets mentioned in older Rails documentation and tutorials, but it no longer describes the default pipeline.
Where SHA-256 Actually Does Show Up in Propshaft: Subresource Integrity
SHA-256 hasn’t disappeared from the asset layer entirely, it’s just moved to a different job: Subresource Integrity (SRI). Propshaft’s source explicitly restricts SRI hash algorithms to the SHA-2 family, raising an error if you configure anything outside sha256, sha384, or sha512. SRI hashes are what let a browser verify that a fetched asset (including ones loaded from a CDN) hasn’t been tampered with, by comparing a hash embedded in the integrity attribute against the file it actually received.
Sprockets-Rails has supported this for its own asset helpers as well: enabling integrity: true on a tag like javascript_include_tag produces an integrity=”sha256-…” attribute, base64-encoded per the SRI spec, on assets served over HTTPS or localhost.
So the accurate picture is: fingerprinting (the part of the filename) and integrity verification (the browser-facing security check) are two different mechanisms, and SHA-256 is specifically tied to the second one in Propshaft, while it powers both in Sprockets.
Gem Version Identification: SHA-256 Checksums in Bundler and RubyGems
The other half of the question, gem version identification, is really about integrity verification for dependencies, and this is where Bundler’s more recent security work comes in.
Bundler 2.6 introduced built-in checksum verification for gems. When enabled, Bundler records a SHA-256 checksum for every gem version in a CHECKSUMS section of Gemfile.lock. On every subsequent install, Bundler recalculates the checksum of the .gem package it’s about to install and compares it against the value stored in the lockfile. If they don’t match, Bundler raises a “mismatched checksums” error and blocks the install rather than silently installing a potentially tampered package. This applies to every non-local gem in the lockfile, whether it comes from rubygems.org, a private gem server, or an internal registry, and it only activates once a CHECKSUMS section exists in the lockfile, so existing projects aren’t broken by the upgrade.
This checksum verification was specifically framed by the RubyGems team as a defense against supply chain attacks, where a gem’s published contents could be swapped or modified after the version your lockfile expects was originally resolved.
RubyGems.org also exposes SHA-256 checksums per gem version through its public API. A request like rubygems.org/api/v2/rubygems/<gem-name>/versions/<version>.json returns a sha field with that version’s checksum, which is how tooling (including Bundler itself) can independently verify a specific gem version’s package contents against what rubygems.org has on record.
Practical Takeaways
- Don’t assume Rails 8 asset fingerprints are SHA-256. If you’re on Propshaft, they’re SHA-1 digests truncated to 8 characters. This doesn’t weaken cache-busting (collision resistance at that length is irrelevant for this use case), but it matters if you’re writing tooling, documentation, or security reviews that assume a specific hash length or algorithm.
- If you need cryptographic integrity guarantees on assets (protecting against tampering, not just cache busting), that’s what Subresource Integrity is for, and Propshaft deliberately restricts it to the SHA-2 family (SHA-256/384/512).
- Enable Bundler’s checksum verification if you haven’t already. If your Gemfile.lock doesn’t have a CHECKSUMS section, you’re not getting the supply-chain protection that Bundler 2.6 introduced. Running a recent bundle install/bundle lock with a current Bundler version will populate it.
- Treat “gem version identification” and “gem integrity verification” as related but distinct. The version number in your Gemfile.lock tells Bundler which release to install; the SHA-256 checksum tells it whether the package it downloaded actually matches that release.
Why This Matters for Rails Teams
At Essence Solusoft, we work across both legacy Sprockets applications and newer Rails 8 codebases running Propshaft, and getting these details right matters when we’re doing security reviews, setting cache headers, or auditing a client’s dependency supply chain. Knowing precisely which hash algorithm is doing which job, cache-busting versus tamper detection versus dependency integrity, is the difference between a documentation footnote and catching a real gap in a production audit.
Need a Rails security or dependency audit for your application? Get in touch with Essence Solusoft.
