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
Scanned 5/27/2026
Install via CLI
openskills install Habitat-Thinking/ai-literacy-superpowers---
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
- [ ] Automated vulnerability scanner is run in CI (not just locally)
- [ ] Direct dependencies are intentional and documented
- [ ] No `replace` directives in `go.mod` pointing to local paths or forks
- [ ] Dependency manifest is committed (not generated at build time)
### Go-specific
- [ ] `go.sum` is committed alongside `go.mod`
- [ ] `govulncheck` runs in CI and fails the build on known CVEs
- [ ] No `replace` directives substituting public modules with local or private alternatives
- [ ] `go mod verify` passes (confirms module content matches go.sum hashes)
### Maven/JVM-specific
- [ ] Dependency versions are pinned (no version ranges: `[1.0,2.0)`)
- [ ] OWASP Dependency-Check (or equivalent) runs in CI
- [ ] No dependencies with legacy or low-trust group IDs without provenance verification
- [ ] Transitive dependency tree has been reviewed (`mvn dependency:tree`)
---
## Go: Running the Audit
### Check for known CVEs
```bash
# Install once:
go install golang.org/x/vuln/cmd/govulncheck@latest
# Run from the module root:
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
```bash
# Confirms every module in the build matches its go.sum hash.
# Fails if any module has been tampered with or if go.sum is stale.
go mod verify
```
### Check for suspicious replace directives
```bash
# Print any replace directives in go.mod:
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
```bash
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)
```bash
# Run from the project root (downloads NVD data on first run — takes ~5 min):
mvn org.owasp:dependency-check-maven:check
# HTML report is generated at:
# target/dependency-check-report.html
```
### Review the dependency tree
```bash
# Show all direct and transitive dependencies with versions:
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)
```bash
# Version ranges in pom.xml allow Maven to silently pull newer versions:
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
```yaml
- 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>`:
```xml
<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>
<!-- Fail build if any dependency has a CVSS score >= 7 (high) -->
<failBuildOnCVSS>7</failBuildOnCVSS>
</configuration>
</plugin>
```
Then in the CI workflow:
```yaml
- name: Run OWASP dependency scan
working-directory: tui
run: mvn -B org.owasp:dependency-check-maven:check
```
### Dependabot for package updates
```yaml
# .github/dependabot.yml
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
```bash
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
```bash
bundle exec libyear-bundler
```
Same tabular output for Bundler-managed gems.
#### Python
```bash
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
```bash
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:
```markdown
## 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:
```bash
# Using Syft (install from https://github.com/anchore/syft):
syft dir:. -o cyclonedx-json > sbom.json
```
No comments yet. Be the first to comment!