# dependency-vulnerability-audit

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

- **Kind:** skill
- **Source:** https://github.com/Habitat-Thinking/ai-literacy-superpowers
- **Page:** https://forefy.com/skills/1712e0c9-3825-4b52-8068-7c9a335c3239
- **API (JSON + files):** https://forefy.com/api/asr/1712e0c9-3825-4b52-8068-7c9a335c3239

---

## SKILL.md

---
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
```

