Govulncheck Integration with DefectDojo
Govulncheck Integration with DefectDojo
Govulncheck is the Go team's official vulnerability scanner for Go code and binaries, published in the golang.org/x/vuln module. It checks a module's dependencies against the Go vulnerability database (vuln.go.dev), which publishes advisories in the OSV format, and then uses static analysis to work out whether your code actually reaches the vulnerable functions. Govulncheck prints human-readable text by default and can emit JSON or SARIF. DefectDojo imports its native JSON output with two parsers.
Govulncheck Integration with DefectDojo
We picked govulncheck for our Go services because it answers the question most dependency scanners can't: is the vulnerable function called from our code? Running it through DefectDojo keeps that answer attached to a Finding with an owner and an SLA. Using the V2 parser, a vulnerability our code calls becomes a High finding, while one that only sits in a required module lands as Info. The team works the reachable issues first without losing sight of the rest.
Why Govulncheck Matters
Go dependency trees tend to be deep, and most vulnerable modules in them never touch the vulnerable code path. Govulncheck is built to make that distinction.
- It is maintained by the Go team and uses the curated Go vulnerability database, so advisories are specific to Go modules and symbols.
- Reachability analysis reports at three levels: the vulnerable symbol is called, the vulnerable package is imported, or the module is only required.
- Call traces show the path from your code to the vulnerable function, which shortens review.
- Findings include the version that fixes each advisory.
- The Go vulnerability database doesn't publish CVSS scores, so the raw output gives you no severity to drive SLAs. That is the gap DefectDojo's V2 parser fills.
Advantages of This Integration
What we gained by sending govulncheck results through DefectDojo:
- Severity from reachability (V2). Called symbols become High, imported packages Low, and required-only modules Info, so SLA rules automatically focus on vulnerabilities your code reaches.
- Precise deduplication. Both parsers deduplicate on the tool's unique ID: the OSV ID for the original parser, and the OSV ID plus module for V2. The same advisory in the same module always matches the existing Finding.
- Fix tracking. Fixed versions are recorded and DefectDojo's fix available flag is set, so you can filter for upgrades you can make today.
- Lifecycle on reimport. Reimporting each build's output into the same Test mitigates advisories that disappeared after an upgrade and reactivates any that come back.
- One view with first-party code. Govulncheck findings sit on the same Asset as SAST results for the same Go service, such as Gosec findings.
How This Integration Works
DefectDojo has two scan types for govulncheck's native JSON:
- Govulncheck Scanner V2: for the streaming JSON format of current govulncheck releases. It reads the
findingrecords, so advisories that don't apply to your code aren't imported, and it creates one Finding per advisory and module pair. Recommended for new setups. - Govulncheck Scanner: the original parser. It accepts both the older single-document JSON and the streaming format, imports every advisory in the stream, and sets severity to Info.
1. Run govulncheck with JSON output. From the module root:
govulncheck -format json ./... > govulncheck.json
Older govulncheck releases used -json instead of -format json. If you produce SARIF with -format sarif, import it with DefectDojo's generic SARIF scan type. The Govulncheck parsers reject SARIF files with an error that says so.
2. Import the report. In the UI, open the Engagement, choose Import Scan Results, select the scan type, and upload the file. To automate (Community Edition and DefectDojo Pro):
curl "https://YOUR_INSTANCE/api/v2/import-scan/" \
-H "Authorization: Token $DD_API_TOKEN" \
-F "scan_type=Govulncheck Scanner V2" \
-F "file=@govulncheck.json" \
-F "product_name=inventory-api" \
-F "engagement_name=CI" \
-F "minimum_severity=High" \
-F "auto_create_context=true"
Setting minimum_severity=High keeps only reachable findings, which matches govulncheck's default text output. Drop it to import package and module level results too.
DefectDojo Pro users can use Universal Importer:
universal-importer import \
--defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/" \
--scan-type "Govulncheck Scanner V2" \
--report-path "./govulncheck.json" \
--product-name "inventory-api" \
--engagement-name "CI" \
--auto-create-context
3. Reimport on every build. Send later output to /api/v2/reimport-scan/ against the same Test.
Data Granularity: What Gets Imported
| DefectDojo Field | Source in govulncheck JSON | Notes |
|---|---|---|
| Title | OSV id and module |
V2: "GO-ID - module". Original: "GO-ID - package - import path" |
| Severity | Reachability level (V2) | symbol: High, package: Low, module: Info. Original parser: Info |
| Description | OSV summary, details, traces |
V2 adds module version and reachability. Original adds vulnerable functions and affected version ranges |
| CVE | First OSV aliases entry |
Usually the CVE or GHSA ID. Empty for Go-only advisories |
| Component Name / Version | Module and version from the trace | Recorded as a Go module dependency |
| Fix Version | fixed_version, or OSV ranges |
Fix available is set when a fixed version exists |
| References | OSV references |
Each reference with its type, plus the vuln.go.dev database link |
| URL | database_specific.url |
Link to the advisory on vuln.go.dev |
| Impact | OSV details |
Original parser, streaming format |
| File Path | Import path | Original parser, streaming format |
| Unique ID | OSV ID (plus module in V2) | Drives deduplication |
| Deduplication | Unique ID from tool | Both scan types |
Use Cases
As a merge gate for Go services: CI runs govulncheck and imports with V2. Only High findings, meaning the vulnerable symbol is called, fail the build. Package and module level results are still recorded for scheduled upgrades.
For prioritizing a dependency backlog: A team inheriting a service with 40 advisories in its module graph imports once without a severity filter. Sorting by severity shows the handful their code reaches, and the Info findings become a single upgrade task.
When a new Go advisory lands: Searching DefectDojo by the GO ID or CVE across Assets shows which services carry the module and, with V2, which ones actually call the vulnerable function.
Pairing with code scanning: Gosec covers first-party Go code and govulncheck covers dependencies. Importing both into the same Asset gives one picture of risk for each Go service.
Operational Tips
- Choose V2 unless you have reports from older govulncheck versions. The original parser imports every advisory in the stream, including ones that don't affect your code, which inflates counts.
- Don't switch an existing Test between the two scan types. Their unique IDs differ, so a switch looks like every finding was fixed and replaced.
- Reachability can change as your code changes. A finding can move from Low to High on reimport when a new call path appears, so keep alerting on severity increases as well as on new findings.
- Scan the same package pattern (for example
./...) every time. Narrowing it changes reachability and can mitigate findings that still exist elsewhere in the module. - Go-only advisories may have no CVE alias. Search by the GO ID in the title when CVE filtering comes up empty.
- Use the Fix Version field to batch upgrades: several advisories in one module often share a fixed version.