All integrations

Bundler-Audit Integration with DefectDojo

Bundler-Audit Integration with DefectDojo

Bundler-Audit is an open source command-line tool from the RubySec project that checks a Ruby application's dependencies for known vulnerabilities. It reads Gemfile.lock, compares each locked gem version against the Ruby Advisory Database, and reports every gem with a matching advisory, including the CVE or GHSA identifier, a criticality rating, an advisory URL, and the versions that fix it. It also warns about insecure gem sources. DefectDojo imports the plain text output of bundle-audit check.

Bundler-Audit Integration with DefectDojo

Bundler-Audit is the quickest way we know to answer whether a Ruby app ships a gem with a published advisory, and it costs almost nothing to run in CI. What it lacks is memory. Importing its output into DefectDojo turns each vulnerable gem into a Finding on the Asset that owns the app, with the CVE attached, an SLA based on criticality, and an owner. When someone bumps the gem in Gemfile.lock, the next reimport closes the Finding, so we can show which advisories were fixed and how long they took.

Why Bundler-Audit Matters

A typical Rails application locks well over a hundred gems, most of them transitive. Few teams track advisories for all of them by hand.

  • It works from Gemfile.lock, so it reports the exact versions the app will run, including transitive dependencies.
  • The Ruby Advisory Database is community maintained and focused on the Ruby ecosystem, and bundle-audit update keeps the local copy current.
  • Each result includes a Solution line listing the patched version ranges, which tells a developer exactly what to upgrade to.
  • It runs offline after the database update and finishes in seconds, which makes it easy to add to any pipeline.
  • Its output is a snapshot. Without a platform behind it, nobody can tell how long a vulnerable gem has been in production.

Advantages of This Integration

What we gained by sending Bundler-Audit output through DefectDojo:

  • CVE-level tracking. The parser stores the CVE (or GHSA, when there is no CVE) as the Finding's vulnerability ID, so gem advisories can be searched and reported by identifier across every Asset.
  • Component data. Gem name and version are set as the Finding's component, which makes component-level reporting and filtering work for Ruby apps.
  • Lifecycle on reimport. Reimporting into the same Test mitigates advisories that disappeared after an upgrade, adds new ones, and reactivates any that came back after a downgrade.
  • Deduplication. Bundler-Audit findings use DefectDojo's legacy deduplication on title, CWE, line, file path, and description, and the parser also collapses repeated entries within a report.
  • SLAs and ticketing. Gem advisories get SLA clocks, assignment, risk acceptance, and Jira push alongside findings from other scanners.

How This Integration Works

DefectDojo imports Bundler-Audit results with the Bundler-Audit Scan scan type, which reads the plain text output of bundle-audit check.

1. Produce a text report. From the application directory, update the advisory database and run the check, saving standard output to a file:

bundle-audit check --update > bundler-audit.txt

The parser splits the output into blocks separated by blank lines and reads each block that starts with Name:. It understands the Name, Version, Advisory, CVE, GHSA, Criticality, URL, Title, and Solution lines, which covers both older output (with an Advisory: line) and newer output (with separate CVE: and GHSA: lines). Bundler-Audit's JSON format is not read by this parser.

2. Import it. In the UI, open the Engagement, choose Import Scan Results, select Bundler-Audit Scan, and upload the file. For automation, use the API, available in Community Edition and DefectDojo Pro:

curl "https://YOUR_INSTANCE/api/v2/import-scan/" \
  -H "Authorization: Token $DD_API_TOKEN" \
  -F "scan_type=Bundler-Audit Scan" \
  -F "file=@bundler-audit.txt" \
  -F "product_name=storefront" \
  -F "engagement_name=CI" \
  -F "auto_create_context=true"

DefectDojo Pro users can run the same import with Universal Importer:

universal-importer import \
  --defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/" \
  --scan-type "Bundler-Audit Scan" \
  --report-path "./bundler-audit.txt" \
  --product-name "storefront" \
  --engagement-name "CI" \
  --auto-create-context

3. Reimport on each build. Send later reports to /api/v2/reimport-scan/ against the same Test, so gem upgrades show up as mitigated findings in one history.

Data Granularity: What Gets Imported

DefectDojo Field Source in Bundler-Audit Output Notes
Title Name, Title, advisory ID Formatted as Gem name: advisory title [ID]
Severity Criticality Low, Medium, High, Critical pass through. Unknown or missing becomes Medium
Vulnerability IDs CVE or Advisory, else GHSA CVE preferred; GHSA used only when no CVE or Advisory line exists
Description Name, Version, advisory ID Short summary stating the gem has known security issues
Mitigation Solution Patched version ranges, for example upgrade to ~> 2.1.3, >= 2.2.0
References URL Advisory link
Component Name / Version Name, Version The locked gem and version
Date Import time The text output has no timestamp, so the import date is used
Finding type Static All findings are marked static
Deduplication Legacy algorithm Title, CWE, line, file path, description

Within one report, entries with the same gem, version, advisory ID, and severity are imported once. The parser does not set a CWE or file path.

Use Cases

In a CI pipeline: Each build runs bundle-audit check --update and reimports the result into a Test for the main branch. When Dependabot or a developer bumps a gem, the matching Finding is mitigated on the next build without manual cleanup.

Across many Rails apps: A team maintaining a dozen Ruby services imports each into its own Asset, then searches DefectDojo by CVE when a new Rack or Rails advisory lands to see every affected app at once.

For release sign-off: Before a release, the team checks the Asset for open High and Critical gem advisories. Anything that can't be upgraded yet is risk-accepted with an expiry, so the decision is recorded.

Alongside Brakeman: Teams already running Brakeman for Rails code import Bundler-Audit to the same Asset, which gives one view of code-level and dependency-level risk for the app.

Operational Tips

  • Always run with --update (or bundle-audit update first). An outdated advisory database makes the reimport look like nothing changed, even when new advisories exist.
  • Plan for the Unknown rating. Older advisories without a CVSS score arrive as Medium, so review them during triage instead of trusting the default.
  • Insecure source warnings (for example a git:// or http:// gem source) are not imported, because the parser only reads gem advisory blocks. Check those in the CI log.
  • Capture standard output only. Mixed-in log lines don't break parsing, but stray blocks that start with Name: could.
  • Use risk acceptance with an expiration date for gems you can't upgrade yet, so they come back for review.
  • Tag imports with the app or branch (for example tags=storefront,main) to filter Ruby dependency findings in metrics.