dependency-triage
Turn a vulnerability scan into an ordered list of actions by working out which findings are actually reachable.
Save as .claude/skills/dependency-triage/SKILL.md in a repository, or under ~/.claude/skills/dependency-triage/SKILL.md to have it everywhere. The copy button takes the whole file, frontmatter included.
--- name: dependency-triage description: Turn a vulnerability scan into an ordered list of actions by working out which findings are actually reachable. Use when triaging npm audit, Dependabot alerts, a CVE list, or deciding which dependency upgrades matter. --- # Dependency triage A scanner reports what is installed, not what is exploitable. In a typical report most findings are not reachable in your application, and a few are urgent. Treating them as one undifferentiated list means the urgent ones wait behind the irrelevant ones. The job is ranking, not patching everything. ## For each finding, establish four things ### 1. Is the vulnerable code reachable The question that removes most of the list. - Is the package a direct dependency or pulled in transitively. - Is the vulnerable *function* called, directly or by something you call. A vulnerability in a package's CLI does not affect you if you import its library. - Can attacker controlled input reach it. A parser vulnerability matters when you parse untrusted input and usually does not when you parse your own config at boot. ### 2. Where does it run - Production server code: highest concern. - Client side code: concern depends on whether the attacker is the user. - Build time or development only: usually low, with one exception below. - Test only: normally not urgent. A `devDependencies` finding is not automatically safe. Build tooling runs with repository access and often with credentials, so a compromised build package is a supply chain problem even though it never ships. ### 3. What does exploitation need Network access, authentication, a specific configuration, a user action, or a malicious input you would have to accept. A critical score that needs local root access is less pressing than a medium one that needs an HTTP request. ### 4. What does fixing cost A patch release is minutes. A major version bump across a framework is a project. That difference belongs in the ranking. ## Do not rank by severity score alone The score describes the worst case for anyone using the package. It knows nothing about your application. A critical finding in a package you import but never invoke is lower priority than a medium one on your login path. Say this explicitly when reporting, because the score is what everyone else is looking at. ## Fixing Prefer, in order: 1. Upgrade the direct dependency to a patched version. 2. Upgrade the parent that pins the vulnerable transitive dependency. 3. Override or resolve the transitive version, and record why, because overrides rot silently. 4. Remove the dependency. Often realistic for a small package, and it removes the whole class of future findings. 5. Mitigate in your own code, and document the mitigation next to the finding so nobody removes it later. 6. Accept the risk, with a written reason and a date to revisit. Accepting is a legitimate outcome. Accepting silently is not. ## Traps - **Do not bulk upgrade everything to clear the report.** A clean report bought with an untested major version bump trades a theoretical risk for a real outage. - **Check whether the advisory applies to your version range.** Reports sometimes flag versions that were never affected. - **A withdrawn or disputed advisory is still a finding to explain**, not one to action. - **Look at the fix, not just the version number.** Occasionally the patched release changes behaviour you depend on. ## Report back 1. Act now: reachable, exploitable, on a sensitive path. With the fix. 2. Schedule: real but not urgent, or expensive to fix. 3. Not applicable: with one line each on why, so nobody re triages them. 4. Anything you could not determine, named rather than assumed safe.
what it needs
Nothing. This skill is instructions only, so it works in any agent that reads SKILL.md with nothing installed and no account. Save the file and it is live in the next session.
the instructions, in full
Dependency triage
A scanner reports what is installed, not what is exploitable. In a typical report most findings are not reachable in your application, and a few are urgent. Treating them as one undifferentiated list means the urgent ones wait behind the irrelevant ones.
The job is ranking, not patching everything.
For each finding, establish four things
1. Is the vulnerable code reachable
The question that removes most of the list.
- Is the package a direct dependency or pulled in transitively.
- Is the vulnerable function called, directly or by something you call. A vulnerability in a package's CLI does not affect you if you import its library.
- Can attacker controlled input reach it. A parser vulnerability matters when you parse untrusted input and usually does not when you parse your own config at boot.
2. Where does it run
- Production server code: highest concern.
- Client side code: concern depends on whether the attacker is the user.
- Build time or development only: usually low, with one exception below.
- Test only: normally not urgent.
A devDependencies finding is not automatically safe. Build tooling runs with
repository access and often with credentials, so a compromised build package
is a supply chain problem even though it never ships.
3. What does exploitation need
Network access, authentication, a specific configuration, a user action, or a malicious input you would have to accept. A critical score that needs local root access is less pressing than a medium one that needs an HTTP request.
4. What does fixing cost
A patch release is minutes. A major version bump across a framework is a project. That difference belongs in the ranking.
Do not rank by severity score alone
The score describes the worst case for anyone using the package. It knows nothing about your application. A critical finding in a package you import but never invoke is lower priority than a medium one on your login path.
Say this explicitly when reporting, because the score is what everyone else is looking at.
Fixing
Prefer, in order:
- Upgrade the direct dependency to a patched version.
- Upgrade the parent that pins the vulnerable transitive dependency.
- Override or resolve the transitive version, and record why, because overrides rot silently.
- Remove the dependency. Often realistic for a small package, and it removes the whole class of future findings.
- Mitigate in your own code, and document the mitigation next to the finding so nobody removes it later.
- Accept the risk, with a written reason and a date to revisit.
Accepting is a legitimate outcome. Accepting silently is not.
Traps
- Do not bulk upgrade everything to clear the report. A clean report bought with an untested major version bump trades a theoretical risk for a real outage.
- Check whether the advisory applies to your version range. Reports sometimes flag versions that were never affected.
- A withdrawn or disputed advisory is still a finding to explain, not one to action.
- Look at the fix, not just the version number. Occasionally the patched release changes behaviour you depend on.
Report back
- Act now: reachable, exploitable, on a sensitive path. With the fix.
- Schedule: real but not urgent, or expensive to fix.
- Not applicable: with one line each on why, so nobody re triages them.
- Anything you could not determine, named rather than assumed safe.