Mix Audit Integration with DefectDojo
Mix Audit Integration with DefectDojo
Mix Audit (mix_audit) is an open source dependency audit tool for Elixir projects, maintained by Mirego. It adds a mix deps.audit task that checks the packages pinned in mix.lock against the Elixir security advisories data and reports any dependency with a known vulnerability. It prints a human-readable report by default and can write JSON, which is the format DefectDojo imports.
Mix Audit Integration with DefectDojo
We added Mix Audit to our Elixir services because it is the natural fit for Hex dependencies, and it runs in seconds as a Mix task. Feeding its JSON into DefectDojo turns each vulnerable package into a Finding on the right Asset, with the advisory's severity, the GHSA identifier, and the version to upgrade to. When we bump a dependency and reimport, the advisory closes on its own, and our Elixir dependency risk shows up in the same reports as every other language we ship.
Why Mix Audit Matters
Elixir applications depend on Hex packages for web frameworks, database adapters, authentication, and more. A vulnerable version pinned in mix.lock ships with every release until someone updates it.
- It reads
mix.lock, so it checks the versions the build actually uses, not the ranges inmix.exs. - The advisory data is specific to the Elixir ecosystem, and the tool runs as a Mix task inside the project, so it needs no separate scanner setup.
- Each advisory names the vulnerable version ranges and the first patched versions, which tells the engineer exactly what to upgrade to.
- On its own, the report only describes the current lockfile. It has no record of when an advisory first appeared or whether it was accepted.
Advantages of This Integration
Running Mix Audit through DefectDojo gave us:
- Severity you can put an SLA on. Advisory severities map directly to DefectDojo levels (critical, high, moderate, low), and SLA rules apply to Elixir dependencies the same way they do to other ecosystems.
- Package-level deduplication. DefectDojo hashes Mix Audit findings on component name, component version, and the advisory ID, so rescanning an unchanged lockfile does not create duplicates.
- GHSA identifiers attached. The advisory ID, a GHSA identifier, is stored as the Finding's vulnerability ID, so you can search for a specific advisory across every Asset.
- Fix guidance on the Finding. The first patched versions become the mitigation text, so the person assigned the Finding knows which version to move to.
- Lifecycle on reimport. Reimporting after a dependency update mitigates fixed advisories, adds new ones, and reactivates any that return after a downgrade.
- Ownership and ticketing. Findings can be assigned to the service owner, risk-accepted when no fix exists, or pushed to Jira.
How This Integration Works
DefectDojo reads Mix Audit output with the Mix Audit Scan scan type.
1. Produce a JSON report. Fetch dependencies, run the audit once, then run it again with JSON output:
mix deps.get
mix deps.audit
mix deps.audit --format json > mix_audit.json
The first mix deps.audit in a clean checkout can print compiler output before the JSON, which makes the file unparseable. The second run emits JSON only. This is the most common reason an import fails, and the parser's error message says so.
2. Import it. In the UI, open the Engagement, choose Import Scan Results, select Mix Audit Scan, and upload the file. For automation, the API works in Community Edition and DefectDojo Pro:
curl "https://YOUR_INSTANCE/api/v2/import-scan/"
-H "Authorization: Token $DD_API_TOKEN"
-F "scan_type=Mix Audit Scan"
-F "file=@mix_audit.json"
-F "product_name=notifications-service"
-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 "Mix Audit Scan"
--report-path "./mix_audit.json"
--product-name "notifications-service"
--engagement-name "CI"
--auto-create-context
3. Reimport on each build. Send later reports to /api/v2/reimport-scan/ against the same Test, so upgraded packages close their advisories.
Within a single report, the parser keeps one Finding per package, installed version, and advisory, even if the same combination appears more than once.
Data Granularity: What Gets Imported
| DefectDojo Field | Source in Mix Audit Report | Notes |
|---|---|---|
| Title | Package name and advisory title | Formatted as "package: advisory title" |
| Severity | Advisory severity |
critical, high, moderate (or medium), low; missing severity imports as Medium |
| Description | Advisory description, package, installed version, vulnerable ranges, patched versions | Falls back to the title if no description |
| Mitigation | first_patched_versions |
"Upgrade package to X or later"; generic upgrade advice when none listed |
| Component Name | Dependency package | Hex package name |
| Component Version | Dependency version | Version pinned in mix.lock |
| Vulnerability ID from tool | Advisory id |
A GHSA identifier |
| Vulnerability IDs | Advisory id |
GHSA only; the advisory data has no CVE field |
| References | Advisory url |
|
| Publish Date | disclosure_date |
|
| Finding type | Static | Mix Audit reads the lockfile |
| Deduplication | Hashcode | Component name, component version, vulnerability ID from tool |
Use Cases
In a CI/CD pipeline: Every merge runs mix deps.audit twice and reimports the JSON. A new advisory against a pinned package shows up as a new Finding on the service's Asset, and a release check can query the API for active High or Critical findings in that Test.
For dependency upgrade planning: A team reviewing its Elixir services each sprint filters DefectDojo for open Mix Audit findings, grouped by component. The mitigation text gives the target version, which makes the upgrade list concrete.
When an advisory is published: Security searches DefectDojo for the GHSA identifier and finds every Asset still carrying the vulnerable version, without asking each team to rerun their audit.
Across a polyglot organization: Elixir services import into the same Organization as services in other languages, so dependency risk reports cover the whole portfolio rather than leaving the Elixir services out.
Operational Tips
- Always run
mix deps.audittwice in CI and capture only the second run, or the JSON file will contain compiler output and fail to import. - The advisory data has no CVE field, so search and report on GHSA identifiers for Elixir findings. Cross-tool matching on CVE will not include them.
- Advisories with no recorded severity import as Medium. Review those manually if your SLAs are tight.
- Use one Test per repository and reimport into it so advisories close when you upgrade, rather than accumulating across separate Tests.
- Risk-accept advisories with no patched version, with an expiry date, so they come back once a fix is likely.
- Tag imports with the branch or release (for example
tags=main) if you scan several branches into the same Asset.