Most breaches don't start with a supply-chain attack. They start with an ordinary gem that turns out to be exploitable the moment you depend on it. gemsafe reads what your dependencies do, and what your own code does, then decides before any of it ships.
$ bundle install Resolving dependencies... analysing 3 gem(s) analysed 3 gem(s), 2 cached (4.1s) BLOCK report_kit (1.4.0) a request parameter reaches eval at renderer.rb:88 3 gems checked · 1 blocked · 0 quarantined · 0 warnings gemsafe: refusing to install — nothing has been fetched.
What we find
The headlines go to supply-chain attacks: a maintainer account stolen, a backdoor slipped into a release. Those are real, and they're rare. The common case is quieter. An ordinary gem, honestly published and widely used, that is exploitable on its own. Install it and its weaknesses are yours, reachable from your app's front door.
Scan the registry and this is most of what comes back. Not backdoors. Plain exploitable code that nobody flagged:
evalA controller parameter, a request body, a cookie, reaching an
eval or a shell. That's remote code execution, and anyone who can
reach the endpoint has it.
YAML.load or Marshal.load on something a user
controls. One crafted string becomes arbitrary code. It's the shape behind
more than one Rails CVE.
A shell command built by pasting a variable into a string. Give it a filename with a backtick in it and it runs commands nobody wrote.
A gem that fetches a response and evals it. Whoever controls
that host, or the network to it, controls your process.
gemsafe follows untrusted input through the code. Across method calls, through the transforms in between, from the front door to the dangerous call. Then it flags the gems where that input ends up somewhere it shouldn't. The same analysis reads the code your own team wrote, because a flaw is a flaw whoever committed it.
You don't have to be targeted to be exploited.
Why Ruby
Not a claim about the community. A claim about the plumbing. Every one of these is checkable in about a minute, and most Ruby teams have never had cause to look.
| Control | npm | RubyGems |
|---|---|---|
| Lockfile integrity hashes | always on | off by default |
| Packages carrying a signature | ~100% | ~1.4% |
| Switch to skip install-time code | --ignore-scripts | none |
| Build provenance | ~40% of popular packages | in progress |
Meanwhile 2026 has been the worst year on record for gem-borne attacks: 136 trojanised gems in a single July campaign, self-propagating over SSH; tens of thousands of malicious uploads in May, enough that RubyGems suspended new account registration outright.
Every one of those attacks needed the same thing: code running at install time.
In Ruby that means native extensions, and Bundler gives you no way to turn them off. So gemsafe builds the switch that doesn't exist.
How it works
Resolution writes a lockfile without materialising anything, confirmed even
for gems with native extensions. A .gem file is a plain tar.
Downloading one, hashing it, and reading its metadata executes nothing.
That leaves a window where gemsafe knows exactly what is about to be
installed and the gems have not yet been given a chance to act. Every check
happens there. It is a Bundler plugin, hooked on before-install-all
— which fires after resolution and before Bundler fetches, unpacks or compiles
anything. So you keep typing bundle install, and a gem that fails
a check is never downloaded.
Bundler can verify checksums and does it well. It just doesn't by default,
and a half-populated CHECKSUMS block looks protected while
covering only some of your gems. gemsafe audits the whole chain.
Malicious versions are usually caught and pulled within hours. Declining to be first to install anything buys you that window, and needs no detection of any kind to work.
Most projects need four or five gems that compile at install. Every other
gem that wants to run extconf.rb is refused, and a new entry
appearing in a pull request is exactly the signal you want.
gemsafe fetches and verifies gems itself, so the install step needs no network at all. Compile in isolation and a hostile extension has nowhere to send anything.
Depth
Pure-Ruby gems ship readable source. Precompiled ones don't.
nokogiri 1.16.7 publishes eleven platform variants, ten of them
carrying compiled binaries no reviewer opens. A backdoor in the Linux build is
invisible to every developer on a Mac and fires only in production.
So we compare them. Across four consecutive releases of one variant:
| Signal | 1.16.5 → 1.16.7 | → 1.17.0 |
|---|---|---|
| Imported symbols | 0 changed | +6 / −4 |
| Embedded hosts | 0 new | 0 new |
| Binary size | identical | n/a |
| Ruby source across all 11 variants | byte-identical, 76 of 76 files | |
Baselines that tight make a new import or an unfamiliar hostname in a patch release impossible to miss. It is not proof. A careful attacker reuses the imports already there, which is why anything we can't positively clear is quarantined for review rather than waved through, and why the containment above runs regardless.
Detection gets worse as the attacker gets better. Containment doesn't.
Pricing
Per-seat pricing charges you for hiring. But a fifty-person team and a five-person team running the same Rails app carry the same gems, the same transitive tree, and the same risk. Headcount is the wrong meter, so we don't use it.
Both tiers are flat and org-wide. There is no plan to outgrow and no usage to forecast — the difference between them is what gets analysed, not how much. Nothing ever stops scanning because of a quota. Self-hosted and air-gapped deployments are available; talk to us.
The deterministic checks are free forever. Checksum enforcement, cooling-off, the native-code allowlist and isolated installs run entirely on your machine, need no account, and cost us nothing to give away. Open source projects are free on request.
Get in touch →Questions, or want a look for your team? That goes to hello@gemsafe.dev.