---
name: devupdate-audit
description: Run a full dependency audit of a project using the DevUpdate.io MCP server — verified security issues (CVEs/advisories against exact pinned versions, including ones no upgrade fixes), upgrade hygiene, and coverage gaps — then drive each finding to a fix, mitigation, or documented accepted risk. Use when the user asks for a security audit, a dependency audit, "are we affected by CVE-…", "check our deps for vulnerabilities", or a periodic health check. Requires the DevUpdate.io MCP server (https://api.devupdate.io/mcp). Delegates to the devupdate-dependency-upgrades and devupdate-security-triage skills when installed.
---

# Dependency audit with DevUpdate.io

An audit answers three questions, in order: **(1) are we exposed to anything
right now, (2) how far behind are we, (3) what can't we see?** DevUpdate.io
provides the verified facts — advisories matched against your exact pins
(the same OSV/GHSA data `npm audit` / `pip-audit` read, ids attached),
upgrade availability validated against registries, parent-constraint
blocking — and this skill turns them into a complete, evidence-backed audit.
The division of labor: DevUpdate.io knows everything about your
*dependencies*; it never sees your code. **You** have the working tree, so
exposure confirmation (is the vulnerable path actually used here?) is your
job, on your machine.

## Sub-skills

This skill orchestrates two others. If they're installed
(`.claude/skills/`), invoke them by name at the marked steps; otherwise
fetch them first:

- `devupdate-dependency-upgrades` —
  https://devupdate.io/skills/devupdate-dependency-upgrades/SKILL.md
  (the wave-based upgrade playbook)
- `devupdate-security-triage` —
  https://devupdate.io/skills/devupdate-security-triage/SKILL.md
  (the playbook for issues with no clean upgrade)

## Workflow

### 0. Preflight — confirm the tools answer, and diagnose failures accurately

This audit runs on DevUpdate.io's verified data through five tools:
`get_security_issues` and `get_upgrades` (the pair this audit needs), plus
`list_sources`, `get_updates`, and `dismiss_upgrades`. **The DevUpdate.io
server provides all five to every connected client** — its own MCP
instructions list them by name — so a *missing* tool is almost never a
server fault, and reporting it as one sends the user chasing a bug that
isn't there. Before doing any work, confirm the two you need respond; if
something is wrong, report the **accurate** cause and a concrete fix.

If a tool you need isn't loaded, **load it by name first** — many clients
expose MCP tools lazily, so an unloaded tool looks missing but isn't. Then
read what you get:

- **Answered, even "empty"** — "No known security advisories…", "No
  available upgrades…" are real findings. Proceed normally.
- **The call returned an error** — quote it and name the cause + fix:
  - *"scope does not allow this endpoint" / "Invalid or expired … token"* →
    the connection's authorization. Re-authorize the connector, or check the
    grant's scopes at devupdate.io/settings.
  - *plan / tier gate* → the feature isn't on the user's plan
    (devupdate.io/pricing).
  - *transport error / 5xx / timeout* → DevUpdate.io is unreachable or
    erroring — our side or the network, not the user's config. Suggest a
    retry shortly.
- **The tool is absent** — not loadable by name, and no error to quote.
  Since the server provides all five, the likeliest cause is the **client
  rationing tools**: when many MCP connectors are active at once (e.g.
  GitHub + M365 + plugins), the client surfaces only a relevance-ranked
  subset and defers the rest, so a tool it never indexed can't be loaded.
  Say *that* — not "the server doesn't offer it" — and give the fix: **run
  the audit in a session with fewer connectors enabled** (temporarily
  disable the others), and confirm DevUpdate.io itself is connected.

Whatever the cause, **stop and report it with the accurate reason and fix —
never substitute a hand-rolled audit** (registry scans, Docker/CI/runtime
inventory) for a DevUpdate call that didn't answer. A green-looking audit
built around a broken integration is the worst outcome: it spends the trust
the verified data exists to earn. If only one of the core pair is available,
audit with what answered and flag the other with its accurate reason — don't
paper over it, and don't invent a gap for a tool you simply never loaded.

### 1. Establish scope and state

Call `get_security_issues` (no arguments) and `get_upgrades` (no arguments).
Together they give you the audit surface: every advisory that affects a
pinned version **regardless of whether an upgrade exists**, plus the
per-lockfile rollup `get_upgrades` leads with (which lockfiles exist, how
many dependencies are monitored vs. not, how far behind). The security half
is the key difference from looking at upgrades alone: a dependency can be
vulnerable while sitting at its latest release, and only `get_security_issues`
shows that.

If the project has lockfiles DevUpdate.io doesn't know about (compare
against the working tree), note them now — they're audit scope you'll cover
in step 4.

**Mind which snapshot you're auditing.** These tools report DevUpdate.io's
*stored* view of each lockfile, not your working tree. For a GitHub-connected
lockfile that view is the connected branch as DevUpdate.io last fetched it —
re-synced automatically about hourly, so it can trail a just-pushed change by
up to that long and never reflects uncommitted or feature-branch edits in your
checkout. For a manually uploaded lockfile it's frozen at the last upload. So
if your working-tree lockfile disagrees with what the tools describe (versions
you just bumped, a lockfile you just regenerated), trust the working tree, sync
or re-upload before relying on the audit, and note the divergence in the
report.

### 2. Security issues, ordered by `fix_status`

`get_security_issues` classifies every issue by what resolving it takes.
Work severity-first within each class:

| `fix_status` | Meaning | Resolution path |
|---|---|---|
| `fix_available` | Fix ships in your `(pinned, latest]` range, takeable directly | → **devupdate-dependency-upgrades** skill, wave 1 |
| `fix_blocked` | Fix exists but a parent constraint pins you below it (constraint included) | → upgrades skill, wave 1 blocked-critical path (parent upgrade or override/resolution) |
| `fix_unreleased` | The advisory has no released fix that your range can reach — you cannot upgrade out of it | → **devupdate-security-triage** skill |

Two rules that make the audit honest:

- **Confirm exposure before resizing severity.** Each issue names its
  advisory ids — open them (linked to osv.dev) and check whether the
  vulnerable function, module, or configuration is actually used in this
  codebase (grep imports, call sites, config). Record what you find either
  way. You may *report* an issue as likely-unreachable with evidence; never
  silently drop it on a hunch, and never skip the fix when it's cheap to
  take regardless.
- **`MAL-*` advisory ids mean malicious package, not vulnerable package.**
  Don't triage — remove or replace immediately, check whether install
  scripts ran (lockfile install history, postinstall hooks), and rotate any
  secrets the build environment exposes. Treat it as an incident, not an
  upgrade.

### 3. Upgrade hygiene

With security handled, run the **devupdate-dependency-upgrades** skill for
the remaining waves (routine batch, then careful majors). If the user asked
only for a *security* audit, skip the waves but still report the headline
counts from step 1 — "how far behind" is part of the audit's findings even
when fixing it is out of scope.

### 4. What we can't see

Close the visibility gaps explicitly; an audit that's silent about its
blind spots isn't one.

- **Unmonitored dependencies** (the `not monitored` count from step 1):
  DevUpdate.io has no data for them. Run the ecosystem's registry audit
  (`npm audit`, `pip-audit`, `cargo audit`, `osv-scanner`) **scoped to that
  gap** and fold the findings into the same fix/triage paths above.
- **Unknown lockfiles** from step 1: run the registry audit there too, and
  suggest adding them to DevUpdate.io so the next audit starts with full
  coverage.
- **Freshness**: DevUpdate.io's advisory view refreshes daily and lags OSV
  by up to one cycle. For monitored dependencies the registry audit should
  only *confirm* the `security` findings (same database); if the two ever
  disagree, say so explicitly in the report and trust the fresher source.

### 5. Report

The deliverable is an audit report, not a diff. Structure it as:

1. **Fixed** — issues resolved this session: package, advisory ids, the
   version taken or override applied.
2. **Mitigated** — issues with a workaround applied (from the
   security-triage skill): the advisory's mitigation, where it was applied,
   and the trigger to revisit (e.g., "fix ships upstream").
3. **Accepted risk** — issues deliberately left open: advisory id,
   severity, your exposure assessment (with the evidence from step 2), who
   should re-decide and when. Persist this in the repo (e.g.,
   `SECURITY-NOTES.md` or the team's risk register) — DevUpdate.io will
   keep listing unresolved issues on every audit *by design*; the register
   is how the next session tells "known and accepted" from "new".
4. **Coverage** — monitored vs. unmonitored counts, lockfiles audited,
   gaps closed or remaining.
5. **Behind-latest posture** — the step-3 summary (direct vs. blocked
   split), even if no upgrades were taken.

Every claim in the report should carry its advisory id or upgrade id —
the reader (human or agent) should be able to verify any line against
osv.dev or the registry without trusting this report, the same way the
report didn't have to trust DevUpdate.io.

## Pitfalls

- An empty `get_upgrades` list does **not** mean "no security issues" —
  vulnerable-at-latest only appears in `get_security_issues`.
- Don't dismiss upgrades to make security issues disappear: dismissal
  snoozes *upgrades*; unresolved advisories keep showing until actually
  resolved. That's intentional.
- The audit's authority comes from receipts. If you can't verify a claim
  (advisory id missing, registry disagrees), report the discrepancy rather
  than papering over it in either direction.
