| name | dependency-vulnerability-audit |
| description | Use when auditing project dependencies for known vulnerabilities, supply chain risk, or provenance issues — covers Go modules, Maven/JVM, and CI integration for automated scanning |
Dependency Vulnerability Audit
Overview
Dependencies are the largest attack surface in most projects. This skill provides a structured audit process for Go and Maven/JVM projects, combining static manifest review with tool-driven vulnerability scanning.
Critical rule: Never judge a dependency as safe or unsafe based on your knowledge of its version number. Version numbers in your training data are stale. Always run the tools.
Audit Checklist
For every project
Go-specific
Maven/JVM-specific
Go: Running the Audit
Check for known CVEs
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
govulncheck cross-references the Go vulnerability database (https://vuln.go.dev/) against the specific functions your code actually calls — not just which modules are present. This means fewer false positives than tools that flag any version of a module with any CVE.
Verify module integrity
go mod verify
Check for suspicious replace directives
grep -A1 "^replace" go.mod
A replace directive substituting a public module with a local path (=> ../local-fork) or a private fork is a supply chain red flag — it bypasses the module proxy and checksum verification.
List all modules including transitive
go list -m all
Review the output for unfamiliar or unexpected module paths.
Maven/JVM: Running the Audit
Check for known CVEs (OWASP Dependency-Check)
mvn org.owasp:dependency-check-maven:check
Review the dependency tree
mvn dependency:tree
Look for:
- Unexpectedly old versions of well-known libraries
- Multiple versions of the same library (version conflicts)
- Unfamiliar group IDs — especially legacy namespaces (
com.googlecode.*, org.codehaus.*) where maintainer continuity may be uncertain
Check for version ranges (prohibited)
grep -E "\[|,|\)" pom.xml
Any match is a risk: Maven may resolve a different version than was tested.
CI Integration
Go: Add govulncheck to CI
- name: Run vulnerability scan
working-directory: go-tui
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
Maven: Add OWASP Dependency-Check to CI
Add the plugin to pom.xml under <build><plugins>:
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>9.0.9</version>
<executions>
<execution>
<goals><goal>check</goal></goals>
</execution>
</executions>
<configuration>
<failBuildOnCVSS>7</failBuildOnCVSS>
</configuration>
</plugin>
Then in the CI workflow:
- name: Run OWASP dependency scan
working-directory: tui
run: mvn -B org.owasp:dependency-check-maven:check
Dependabot for package updates
version: 2
updates:
- package-ecosystem: gomod
directory: /go-tui
schedule:
interval: weekly
- package-ecosystem: maven
directory: /tui
schedule:
interval: weekly
Dependency Age (libyear)
CVE scanners tell you whether a dependency has a known vulnerability.
They do not tell you how stale your dependency set is overall. A project
can pass every CVE check while silently accumulating years of staleness
across dozens of libraries — each one a growing risk window for
undiscovered vulnerabilities, breaking API changes, and lost upstream
support.
The libyear metric fills this gap. It sums, for every direct
dependency, the number of years between the version you use and the
latest release. A project at 2 libyears is reasonably current; a project
at 15 libyears has significant staleness risk even if no individual
dependency has a CVE today.
Commands per ecosystem
npm
npx libyear
Produces a table showing each dependency, its current version, latest
version, and age in years. The final line gives the total libyear score.
Ruby
bundle exec libyear-bundler
Same tabular output for Bundler-managed gems.
Python
pip list --outdated --format=columns
Python has no single libyear tool with broad adoption. Use
pip list --outdated to get current vs. latest versions, then calculate
the age delta manually: for each outdated package, find the release date
of your pinned version and the release date of latest on PyPI, and sum
the differences.
Go
go list -m -u all
This lists every module dependency and flags those with available
updates. As with Python, calculate libyears manually: compare the date
of your current version tag with the date of the latest version tag for
each module that shows an update.
Recommended thresholds
| Project size | Budget |
|---|
| Small (fewer than 20 direct dependencies) | < 10 libyears |
| Large (20+ direct dependencies) | < 20 libyears |
These are starting points. Adjust based on your risk tolerance and
release cadence.
How to read the output
- Total libyears is the headline number — track it over time.
- Single-dependency hotspots over 3 libyears indicate concentrated
risk. Prioritise those updates even if the total is within budget.
- Week-over-week increase means staleness is accumulating faster
than you are updating. The GC rule flags this trend automatically.
Report Format
After completing the audit, produce a findings table:
## Dependency Audit
| Ecosystem | Finding | Severity | Fix |
| --- | --- | --- | --- |
| Go | `govulncheck` not in CI | Medium | Add govulncheck step to go-tui-tests.yml |
| Maven | OWASP Dependency-Check not in CI | Medium | Add plugin + CI step |
| Maven | `lanterna:3.1.1` — legacy com.googlecode group ID | Low | Verify provenance once; monitor for updates |
| All | No dependabot.yml for packages | Medium | Add gomod + maven ecosystems to dependabot.yml |
Severity guide:
- Critical — actively exploited CVE in a direct dependency
- High — CVE with CVSS ≥ 7 in direct or transitive dependency
- Medium — no scanner in CI; unverified provenance; stale unpinned dependency
- Low — legacy group ID with no known CVE; minor hygiene
What the Tools Cannot Catch
- Malicious code with no published CVE — a new supply chain attack has no CVE until discovered. Tools only know about known vulnerabilities.
- Your knowledge of version numbers — do not assert that a version "doesn't exist" or "seems wrong" based on training data. Module proxy and go.sum are the ground truth; tool output is the authority.
- Semantic correctness of a dependency — tools verify identity and known CVEs, not whether a library does what its README claims.
For highest assurance, generate an SBOM and sign it:
syft dir:. -o cyclonedx-json > sbom.json