Departments / security / dependency-remediation

dependency-remediation

Use when dependency-audit has produced CVE findings and you need to close them. Triages each finding into upgrade / transitive override / patch / replace / accept-with-mitigation, applies the fix per ecosystem (npm, pip, go, cargo, maven), verifies with tests, updates SBOM and lockfiles, and writes the audit trail.

Department

Security

Safety

writes-shared
Writes shared state

Supported stacks

Stack-agnostic — no detection required.

Produces

security/remediation/dependencies-<date>.md

Consumes

  • security/findings/dependencies.json

When to use

Do not use this skill to scan for vulnerabilities — that’s dependency-audit. Do not use it for secret leaks in dependency manifests — that’s secret-remediation.

Inputs

Outputs

Tool dependencies

Procedure

  1. Triage findings into one of five buckets. For each finding in dependencies.json:

    BucketCriteria
    Upgrade directPackage is declared in the manifest + fix version exists.
    Transitive overridePackage is a sub-dependency + fix version exists but parent hasn’t updated.
    No patch — replaceNo fix available + a maintained alternative exists with compatible API.
    No patch — acceptNo fix, no alternative. Must justify with compensating control.
    False positiveCVE does not apply to our usage (e.g. server-only CVE in a build-time dep).
  2. Upgrade direct — run the canonical command per ecosystem:

    npm / yarn / pnpm:

    npm install lodash@^4.17.21
    # or:
    yarn upgrade lodash@^4.17.21
    # verify
    npm ls lodash
    npm audit --production

    pip / poetry:

    # poetry
    poetry add 'urllib3>=2.2.2'
    # or constrained pip-tools
    echo 'urllib3>=2.2.2' >> constraints.txt
    pip-compile --upgrade-package urllib3
    # verify
    pip-audit

    Go:

    go get github.com/gin-gonic/gin@v1.10.0
    go mod tidy
    govulncheck ./...

    Cargo:

    cargo update -p tokio --precise 1.38.0
    cargo audit

    Maven:

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.17.1</version>
        </dependency>
      </dependencies>
    </dependencyManagement>

    Then mvn dependency-check:check.

  3. Transitive override — force the sub-dependency version at the package manager level.

    npm (≥ 8.3):

    {
      "overrides": {
        "minimist": "1.2.8"
      }
    }

    Then npm install and verify with npm ls minimist — every entry should be ≥ 1.2.8.

    yarn (Berry / classic 1.x):

    {
      "resolutions": {
        "**/minimist": "1.2.8"
      }
    }

    pnpm:

    {
      "pnpm": {
        "overrides": {
          "minimist": "1.2.8"
        }
      }
    }

    pip: add to constraints.txt and rebuild requirements.txt via pip-compile --constraint constraints.txt.

    Go: use replace in go.mod:

    replace github.com/bad/transitive v1.0.0 => github.com/bad/transitive v1.0.3

    Cargo: [patch.crates-io] stanza in Cargo.toml.

  4. Replace — when no patch and no parent update are viable, find a maintained alternative.

    • Check the ecosystem’s maintenance signals: last-release date, open-issue count, download trend.
    • Confirm API compatibility or plan the migration (codemod script, compatibility shim).
    • Stage the replacement in a small PR with a before/after diff table.
  5. Test the upgrade. Never ship a dependency bump without running:

    • Full unit test suite.
    • Integration tests that exercise the upgraded library (if no existing coverage, add a smoke test hitting the API path).
    • For major-version bumps, read the upgrade guide / changelog and grep the codebase for any deprecated API used.
    • For security-relevant changes (e.g. auth library), write an explicit regression test asserting the vulnerable behavior no longer occurs.
  6. Regenerate and commit the SBOM.

    cyclonedx-bom -o sbom.json
    # or
    syft . -o cyclonedx-json > sbom.json
    git add sbom.json
  7. Open the PR using this body template:

    ## CVEs closed
    - CVE-2020-8203 (HIGH, CVSS 7.4) — lodash < 4.17.19
    
    ## Changes
    | Package | Before | After | Reason |
    |---|---|---|---|
    | lodash | 4.17.15 | 4.17.21 | direct upgrade |
    
    ## Test evidence
    - `npm test` — all 327 suites pass (https://ci…/run/1234).
    - Manual smoke test against `/api/orders` — pass.
    
    ## SBOM delta
    See `sbom.json` diff. 1 package updated, 0 added, 0 removed.
  8. Accept-with-mitigation requires explicit documentation. If you cannot upgrade / override / replace:

    • Why not (date-bound reason, e.g. “vendor patch ETA 2026-05-15” or “blocks prod due to breaking change”).
    • Compensating control (WAF rule, network isolation, feature flag, runtime patch such as aikido-zen / snyk runtime).
    • Review date (no more than 60 days away).
    • Owner.
  9. Write remediation report. security/remediation/dependencies-<date>.md contains:

    • Summary: total CVEs in audit, closed / accepted / residual counts.
    • Per-CVE table: ID, severity, package, action taken, PR link, test evidence.
    • Exceptions register with review dates.
    • Re-audit result (ideally 0 matching the original CVE IDs).

Examples

Example 1 — direct upgrade with no breaking changes

dependencies.json excerpt:

{
  "findings": [
    {
      "cve": "CVE-2020-8203",
      "severity": "HIGH",
      "cvss": 7.4,
      "package": "lodash",
      "version_current": "4.17.15",
      "version_fixed": "4.17.19",
      "direct": true
    }
  ]
}

Actions:

# 1. Upgrade
npm install lodash@^4.17.21     # pick the latest patched line
# 2. Check lockfile + test
npm ci
npm test                        # 327 pass
# 3. Regenerate SBOM
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
# 4. Commit + PR
git add package.json package-lock.json sbom.json
git commit -m "chore(deps): upgrade lodash to 4.17.21 — closes CVE-2020-8203"
gh pr create --title "deps: close CVE-2020-8203 (lodash)" --body-file .github/pr-body-deps.md
# 5. Re-audit
npm audit --production
# found 0 vulnerabilities

Report excerpt:

### CVE-2020-8203 — lodash prototype pollution
- Severity: HIGH (CVSS 7.4)
- Action: upgraded direct dependency `lodash` 4.17.15 → 4.17.21.
- Test evidence: `npm test` green (run 1234), smoke test on `/api/orders` pass.
- SBOM: 1 package updated.
- PR: #482, merged 2026-04-20T15:42Z.

Example 2 — transitive override with follow-up reminder

dependencies.json excerpt:

{
  "findings": [
    {
      "cve": "CVE-2021-44906",
      "severity": "HIGH",
      "cvss": 9.8,
      "package": "minimist",
      "version_current": "1.2.5",
      "version_fixed": "1.2.6",
      "direct": false,
      "depended_on_by": ["mkdirp@0.5.5"]
    }
  ]
}

mkdirp@0.5.5 is a direct dependency; upgrading it to 0.5.6 pulls minimist ≥ 1.2.6 transitively. But we also have mkdirp pinned via legacy tooling. Use an override:

{
  "overrides": {
    "minimist": "1.2.8"
  }
}
npm install
npm ls minimist
# └─┬ mkdirp@0.5.5
#   └── minimist@1.2.8    # override applied
npm test
npm audit --production    # CVE-2021-44906 no longer reported

Follow-up ticket (filed to tech-debt backlog): “Drop overrides.minimist once mkdirp is upgraded to ≥ 3.0 or replaced with fs.mkdir({recursive: true}).” Owner: @platform. Review: 2026-06-20.

Report excerpt:

### CVE-2021-44906 — minimist prototype pollution
- Severity: HIGH (CVSS 9.8)
- Action: transitive override via `overrides.minimist = "1.2.8"`.
- Verified: `npm ls minimist` shows 1.2.8 in every path.
- Follow-up: TECH-812 — drop override when mkdirp upgraded.
- Re-audit: CVE-2021-44906 not reported.

Constraints

Quality checks

Customise for your organisation

dependency-remediation

The LLM will rewrite this skill for your environment. Your API key and form inputs stay in your browser — only the skill and your environment go to OpenRouter.

One line. Be specific — cloud, language, framework, orchestrator.

Free text that steers the rewrite. Leave blank if nothing specific.

cost estimate: