Put each internal gem inside a source block for its own server, so Bundler installs it from there. The RubyGems security guide also says to give every gem in the Gemfile an explicit source, because a source declared in a block still counts as a candidate for gems without one.
The risk
If your company runs an internal gem server alongside rubygems.org, a public gem published under the same name as an internal gem could be substituted for it. The RubyGems security page describes exactly this. The attacker does not need to break into anything. They only need to publish the name you forgot to claim.
The pattern
source "https://rubygems.org" do
gem "rails"
gem "pg"
end
source "https://gems.internal.example" do
gem "acme-billing"
gem "acme-auth"
end
Every gem sits inside a block. No gem is left to resolve from whichever source answers first.
Common setups and their risk
| Setup | Risk | Better approach |
|---|---|---|
| One global source line, internal gems listed without blocks | Name could resolve from the public source | Move each internal gem into a block |
| Internal source in a block, public gems outside any block | Block sources remain candidates for unscoped gems | Wrap public gems in their own block |
| Git or path sources for internal gems | Low, source is explicit | Keep, and pin by revision |
Steps to review a Gemfile
- List every gem name that is internal to your company.
- Check each one is inside a block for the internal server.
- Check every other gem has an explicit source too.
- Register your internal gem names on rubygems.org if you can, or at least check that they are not already taken. Reserved names are covered in our note on RubyGems reserved namespaces.
- Re-run install and read the Gemfile.lock diff. Look at the remote lines for each source.
- Add a CI check that fails if a gem lacks an explicit source.
How Gemfile.lock helps
The lock file records which source each gem came from. After you restructure the Gemfile, the lock file diff is your evidence that internal gems now come from the internal server. Keep the lock file committed and run installs with frozen mode, as in our guide to frozen and deployment mode.
Try it yourself
Click through it at your own pace, or open it full screen. Check where each package in the inventory was sourced from.
Where Safeguard fits
Safeguard's policies and gates can check dependency changes in a pull request before merge. A free scan shows what it finds today.
Quick check
Is one source block enough?
No. Gems outside any block can still resolve from a block source, so give every gem an explicit source.
Does this apply to Composer too?
The idea is the same. Composer repositories can be limited with the only and exclude options, covered in our Composer guide.
Sources
Last reviewed: 19 October 2026.