The Forgotten Flag: How --trust-policy Works
Most of the times when we use the gem install command, we only ever need to pass it a few flags like the gem version or the path, in the case of a local gem. However, RubyGems has an often overlooked option that allows us to verify the authenticity and integrity of gems before installing them.
This flag that can quietly protect your system from running code you didn’t intend to trust. In this blog post, we’ll explore how RubyGems signing works, what the trust policy actually does, and why enabling it can make your gem installs far more secure.
RubyGems has been around for over 15 years, and since then it’s grown into a massive ecosystem of thousands of gems. But that size also means it’s a tempting target. A compromised RubyGems account, a malicious gem update, or even a typo-squatted gem can lead to arbitrary code execution during a simple gem install command run.
RubyGems doesn’t verify signatures by default, it installs whatever the registry serves. That’s where gem signing and trust policies come in.
Gem Signing
RubyGems has supported PGP signing for years, though it’s not widely used. When a gem author signs a gem, the .gem package is accompanied by a signature file (typically .gem.asc), which includes a digital signature generated with their private key. When installing, RubyGems can verify that signature against the author’s public certificate to ensure:
- The gem hasn’t been tampered with after being signed.
- The gem was produced by a key you trust.
You can create and manage these keys in your local setup and use it to sign your gems. Check details in this RubyGems guide page , it exemplify how you can get a .cert file and share publicly so users can import and verify your signature when installing your gem.
The Forgotten Flag: --trust-policy
When you install a gem from RubyGems, it allows you to optionally apply a trust policy that defines how strictly it should verify signatures.
gem install my_gem --trust-policy HighSecurity
You can also add this policy permanently in your ~/.gemrc config file:
:trust_policy: HighSecurity
When the policy is active, RubyGems checks each gem’s signature and decides whether to continue based on the policy rules. This will apply wether the gem comes from RubyGems.org, a private gem server, a .gem file downloaded from GitHub or GitLab, or even a local file.
For gems built directly from a git repository (using Bundler’s git: option), signature checks are not performed, since these are built from source and not distributed as packaged .gem files. However, for any actual .gem file, whether downloaded from a registry, a private server, or a local path, the trust policy is fully enforced. This distinction is important: only packaged gems can be cryptographically signed and verified, while git sources rely on the integrity of the repository itself.
The Trust Policy Levels
RubyGems ships with a few predefined trust policies under Gem::Security::Policies:
- NoSecurity: Completely disables signature checks (default).
- LowSecurity: Only warns about unsigned gems, but still installs them.
- MediumSecurity: Only installs signed gems and warns about unsigned or untrusted ones.
- HighSecurity: Only installs gems signed by trusted certificates. Unsigned gems are rejected.
- AlwaysVerify: Always checks signatures; fails on missing or invalid signatures.
For most developers and CI environments, MediumSecurity or LowSecurity are the practical choices, they allow you to install unsigned gems, while still warning you about potential risks. HighSecurity is often too strict for most real-world projects, since many widely-used gems are not signed.
Managing Trusted Certificates
Before you can install signed gems under a strict policy, you need to trust the signing key:
# Import a certificate into your local RubyGems trust store
gem cert --add <(curl -s https://example.com/gem-public_cert.pem)
This adds the certificate to your local keyring (usually under ~/.gem/trust/).
You can list your trusted certs with:
gem cert --list
Once trusted, any gem signed by that certificate can be installed with HighSecurity or AlwaysVerify.
Demo: What Happens When a Gem Isn’t Trusted
Let’s simulate it:
gem install unsigned_gem --trust-policy HighSecurity
# or
gem install unsigned_gem -P HighSecurity
Output:
ERROR: While executing gem ... (Gem::Security::Exception)
unsigned gems are not allowed by the High Security policy
That’s it! RubyGems just prevented an unverified gem from touching your system.
Custom Trust Policies
You can go beyond the built-ins by creating your own subclass of Gem::Security::Policy.
For example, you could enforce that gems must be both signed and SHA256-hashed with a known digest, or integrate your organization’s internal PKI.
Example:
require 'rubygems/security'
class MyCompanyPolicy < Gem::Security::HighSecurity
def verify_chain(chain)
super && chain.certificates.all? { |c| c.subject.include?("YourCompany") }
end
end
This kind of customization allows teams to gate gem installs to signers only.
Why this matters
Using RubyGems’ trust policies can help mitigate a class of threats that have already affected other ecosystems (npm, PyPI, etc.).
Most Ruby developers don’t realize the tooling already exists in RubyGems and it’s just underused.
Conclusion
Security is a top priority for applications, and RubyGems’ trust policies are a powerful tool to help protect your supply chain. However, because gem signing is not widely adopted in the Ruby ecosystem, using the strictest HighSecurity policy can be impractical, it will block your application from bundling most gems, even the most popular ones. Unless you’re willing to fork and re-sign every dependency yourself, you’ll likely need to settle for a more balanced policy like MediumSecurity or LowSecurity. Until gem signing becomes the norm, it’s important to stay aware of these trade-offs and use the best security practices available to you.
If you need help navigating Ruby security or want to ensure your next audit passes smoothly, we offers services to support you through every step reach out to us .