bundler-audit: patch-level verification for Bundler lockfiles
Patch-level verification for Bundler
At a glance
- What is it?
- bundler-audit checks a Gemfile.lock against the ruby-advisory-db and reports vulnerable gem versions, insecure sources and ignored advisories. It is a small, offline-first gem for Ruby teams that want a lockfile check in CI.
- Who is it for?
- Adopt bundler-audit if your deployable artifact is a Gemfile.lock and you want a fast, offline check that fits a CI job. Do not adopt it if your application ships JavaScript, Python or system packages, because it reads only Ruby gem dependencies.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What bundler-audit checks, and what it refuses to check
The project describes itself as patch-level verification for Bundler. Concretely, it reads a Gemfile.lock and compares the resolved gem versions in it against the ruby-advisory-db, a separate repository of advisory records. The README lists four things it looks at: vulnerable versions of gems, insecure gem sources written as http:// or git://, advisories a team has chosen to ignore, and the advisory text itself, which it prints. It does not resolve dependencies, does not modify your Gemfile, and does not scan application code.
That boundary matters. A lockfile is the artifact that actually gets deployed, so checking the lockfile catches a transitive dependency pinned to a bad version even when nobody typed that gem name by hand. The flip side is that bundler-audit has no opinion about code you wrote. A SQL injection in a controller is invisible to it. Teams that expect a general security scanner will be disappointed; teams that want one narrow question answered reliably will not.
The audience is Ruby teams with a committed Gemfile.lock and a CI pipeline. If your project does not commit a lockfile, or resolves gems at deploy time, there is nothing stable for the tool to read.
How the check works: lockfile parsing plus a local advisory database
The mechanism is deliberately simple. bundler-audit parses Gemfile.lock, walks the resolved gems, and looks each one up in a local copy of ruby-advisory-db. The README states plainly that it does not require a network connection, which is the design consequence of keeping that database on disk rather than querying a remote API per gem.
Because the database is local, freshness is your problem. The update command shells out to git and pulls the advisory repository, and the README shows the git output scrolling past: counting objects, compressing, then a fast-forward over files under gems/. Each advisory is a YAML file in that repository, named after the gem and an advisory identifier such as OSVDB-98629.yml. When the pull finishes, the tool prints a count, and the README's example ends with ruby-advisory-db: 64 advisories. That number is the honest signal of how current your copy is.
The output format is one block per finding: gem name, version, advisory ID, criticality, URL, title and a solution line naming the patched version ranges. The README's sample output closes with Unpatched versions found!, which is the string a CI job keys on. There is no scoring model and no severity aggregation, so anything that consumes the result has to do its own prioritisation.
Installing bundler-audit and running a first check
The README gives one install command. It installs the gem globally, and the requirements list git, ruby >= 2.0.0, rubygems >= 1.8, thor ~> 1.0 and bundler >= 1.2.0. git is not optional, because updating the advisory database is a git operation.
gem install bundler-auditIf git is missing, the README has per-platform install lines, including sudo apt install git on Debian and Ubuntu, sudo dnf install git on RedHat and Fedora, apk add git on Alpine Linux, and brew install git on macOS.
Before the first audit, pull the advisory database so the check has something to compare against. The README shows the git transfer output and then the advisory count.
bundle-audit updateThen run the check against the lockfile in the current directory. With no arguments the tool audits Gemfile.lock and prints a block per finding, or nothing if the lockfile is clean.
bundle-auditFor a CI job the README recommends combining the two so the database is refreshed inside the run. The example is bundle-audit check --update; the paired form, bundle-audit check --no-update, checks without touching the database, which is what you want when the network is unavailable or when a previous step already updated it. A custom lockfile path goes through --gemfile-lock Gemfile.custom.lock, and machine-readable output through --format json, optionally with --output bundle-audit.json to write it to a file.
Ignoring advisories without losing the audit trail
Every real project eventually has a finding it cannot fix immediately: a transitive dependency whose parent has not released, or a vulnerability that does not apply to how the gem is used. bundler-audit handles this with an explicit ignore list rather than a silent allowlist. The per-project file is .bundler-audit.yml, and the README gives its shape as a YAML document with an ignore key holding an array of advisory IDs.
---
ignore:
- CVE-YYYY-XXXXA one-off ignore can be passed on the command line instead, as in bundle-audit check --ignore OSVDB-108664. A different config file is selected with --config, for example bundle-audit check --config bundler-audit.custom.yaml.
The design choice here is worth naming. Ignored advisories stay visible in the configuration file, so the exception is reviewable in a pull request and attributable to a person. The cost is that nothing expires. An entry added for a gem you plan to upgrade next sprint will still be suppressing that advisory a year later if nobody removes it. The README documents no expiry date, no comment convention and no warning for stale ignores, so the discipline has to come from code review.
Rake tasks, JSON output and where the tool fits in CI
For projects that already drive everything through Rake, the README shows a three-line integration: require 'bundler/audit/task' followed by Bundler::Audit::Task.new in the Rakefile. That exposes rake bundle:audit and rake bundle:audit:update. The second task is the one that matters on a build machine, since it refreshes the database before the check.
The JSON format is the other integration point. bundle-audit check --format json emits structured findings, and adding --output bundle-audit.json writes them to a file rather than stdout. That file is what you would archive as a build artifact or feed into a dashboard. The README does not document the JSON schema, so treat the field names as something to inspect from a real run before writing a parser against them.
One practical constraint sits in front of all of this: the update step needs git and network access. A build container that blocks outbound connections can still run bundle-audit check --no-update, but only against whatever advisory snapshot the image was built with. That snapshot ages silently, and the only clue to its age is the advisory count printed by the update command.
Where bundler-audit is the wrong tool
The clearest failure mode is scope. bundler-audit reads Ruby gem dependencies. A Rails application that ships a JavaScript bundle, a Python worker and a base container image has three other dependency surfaces that this tool never sees. Running it and declaring the application audited is a category error, not a gap in coverage.
The second limitation is that it reports, it does not fix. The solution line names patched version ranges, but the tool does not edit your Gemfile or run bundle update. If a transitive dependency is pinned by a parent gem that has not released a fix, knowing the advisory ID does not unblock you, and the ignore list becomes the only available answer.
Third, the quality of the result depends entirely on ruby-advisory-db. An advisory that has not been filed is not reported. The README's example output is full of OSVDB identifiers, a numbering scheme that reflects the database's history rather than any live feed. Nothing in the README claims completeness, and no tool of this kind can.
Finally, the requirements list ruby >= 2.0.0, which says the tool is meant to run on old interpreters, but that is a floor, not a promise about every modern Ruby and Bundler combination. If your pipeline runs an unusual Ruby build, verify the gem installs and the check runs before wiring it into a required job.
bundler-audit versus Brakeman
The two tools are frequently mentioned together, and the difference is the layer they inspect. Brakeman reads Ruby application source and looks for insecure patterns in your own code: unsafe interpolation, mass assignment, unescaped output. bundler-audit reads Gemfile.lock and looks at the versions of code you did not write. One answers whether your code has a flaw; the other answers whether a dependency you installed is known to have one.
That means they are complements, not substitutes, and neither one's output reduces the other's value. A project can pass a Brakeman scan with no warnings and still be running a gem version with a published advisory, because the vulnerable code lives in the gem, not in the application. The reverse is equally possible: a lockfile with no findings and a controller with an injection bug.
If you are choosing where to start, the deciding question is what you can change quickly. A vulnerable gem version is often a one-line Gemfile edit and a bundle update. An application-level flaw needs a code change, a test and a review. bundler-audit tends to produce the cheaper fixes, which is also why its findings are worth automating early.
Licence, maintenance and the real upgrade cost
bundler-audit is released under the GNU General Public License, version 3 or later. The README carries the standard GPL preamble, including the warranty disclaimer and the pointer to https://www.gnu.org/licenses/. For most teams the practical question is whether the GPL reaches their own code. Running a GPL-licensed command-line tool as part of a build is a different situation from linking GPL code into a distributed application, but that distinction is a legal question and this article is not legal advice. If your organisation has a licence policy, route it through the people who own that policy before adding the gem to a shipped dependency list.
The repository is not archived, and the last push was on 2026-09-22. The most recent release listed is v0.9.3 from 2025-11-28, following v0.9.2 in 2024-08-22. Those dates describe a project that ships infrequently, which is consistent with its scope: the tool's job is to compare versions, and the advisory data lives in a separate repository that updates independently. A quiet release cadence here is not the same signal it would be for a framework.
The upgrade cost is low and mostly external. Upgrading the gem is a version bump in a Gemfile or a reinstall. What actually changes between runs is ruby-advisory-db, pulled by git, and that is where new findings appear without any change to your code. The README also states a policy on generative AI contributions: a human-in-the-loop is strictly required, contributors must personally review and take responsibility for their work, and unreviewed machine output will be closed. If you plan to send a patch, read that section first.
Editorial conclusion
Adopt bundler-audit if your deployable artifact is a Gemfile.lock and you want a fast, offline check that fits a CI job. Do not adopt it if your application ships JavaScript, Python or system packages, because it reads only Ruby gem dependencies. Before trusting it, run bundle-audit update once and confirm the advisory count printed at the end, then decide whether to commit a .bundler-audit.yml with explicit ignore entries or rely on --no-update in CI.
Frequently asked questions
How do I install bundler-audit?
The README gives a single command, gem install bundler-audit, optionally with sudo. It also lists git as a requirement and provides per-platform install lines for Debian, RedHat, Alpine Linux and macOS.
How do I ignore a specific advisory in bundler-audit?
Pass the advisory ID on the command line with bundle-audit check --ignore OSVDB-108664, or list it under the ignore key in a .bundler-audit.yml file. A different config file can be selected with the --config flag.
How do I update the ruby-advisory-db that bundler-audit uses?
Run bundle-audit update, which pulls the ruby-advisory-db repository with git and prints the resulting advisory count. For CI, the README shows bundle-audit check --update to update and check in one step.
Does bundler-audit need a network connection to run?
The README lists no network requirement among the tool's features and states that it does not require a network connection. Updating the advisory database is the part that uses git and therefore the network.
What is the difference between bundler-audit and Brakeman?
bundler-audit checks gem versions in Gemfile.lock against the ruby-advisory-db, while Brakeman is a static analysis tool for Ruby application code. They inspect different layers and neither replaces the other.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rubysec-bundler-audit)