GitHub Copilot Vulnerable Dependency Remediation

Tested with Opus 4.7 Model compatibility is recorded; source facts remain human-verifiable.

A three-part bundle — a .github/copilot-instructions.md addendum, a GitHub issue template, and an explicit assignment step after the finding is validated. Together they shape the GitHub Copilot cloud agent into a narrow, reviewable dependency remediator: one finding per issue, one draft PR per issue, no auto-merge. Rechecked August 23, 2026: leftover CVE dumps stay development / noindex. Do not invent a named floor. Dependabot-to-agent assignment is generally available for Copilot, Claude, and Codex and still requires GitHub Code Security plus a Copilot plan with coding-agent access. That is not the same as one-step Autofix. The Copilot issue-assignment and agent-tasks APIs remain public preview. Frontmatter model strings stay metadata, not prompt pins.

What this prompt does

When the scanner (or a developer) creates an issue from the security-remediation-dep.yml template and labels it copilot-remediate, the label routes the issue for validation; it does not start the GitHub Copilot cloud agent. After an authorized reviewer confirms the advisory, affected package, repository, and scope, they explicitly assign the issue to Copilot. The cloud agent then reads the repository-level instructions, applies the minimum viable version bump in the affected manifest + lockfile, runs CI, and opens a draft PR linked back to the issue. The agent respects the house rules — no major bumps, no lockfile-only edits, no disabling of tests.

Inputs: finding id + affected package (from the issue body), repository-level instructions (from .github/copilot-instructions.md).
Outputs: a draft PR linked to the issue, passing CI, and a human reviewer assigned via CODEOWNERS.

When to use it

  • You want the shortest-setup remediation path. GitHub-native, no separate orchestration layer.
  • Your scanner already supports projecting findings into GitHub Issues (CodeQL, Snyk, Semgrep, Dependabot alerts converted to issues).
  • You have branch protection on main that requires review and green CI, so the “agent opens a draft PR” pattern is safe.

Don’t use it for:

  • Major version migrations — the repository instructions refuse.
  • Cross-repo fanouts — each repo needs its own instructions and dispatch policy; this prompt is per-repo.
  • First-party SAST findings — use the SDE remediation recipe.

Inputs

  • GitHub issue template fields: finding id, affected package, severity, advisory URLs, scanner notes, workspace hint, direct/transitive evidence, and a copilot-remediate routing label that does not itself dispatch the agent.
  • Repository instructions from .github/copilot-instructions.md, issue body, CODEOWNERS, branch protection, required CI, PR labeling rules, and reviewer routing.
  • Dependency evidence: manifests, lockfiles, package manager, dependency tree, current version, patched range, direct parent for transitive fixes, and ecosystem-specific update commands.
  • Verification evidence: documented lint/test commands, CI status, scanner re-run output, lockfile diff, refused-fix issue comments, and revert instructions.
  • Triage evidence for major bump, prerelease-only, package-not-installed, tests failing, unavailable patch, monorepo workspace scope, and branch or CODEOWNERS restrictions.

The prompt

Two files are checked in to the repository; a validated issue is then dispatched through an explicit assignment step.

.github/copilot-instructions.md — dependency remediation addendum

Append this to your existing copilot-instructions.md:

## Vulnerable dependency remediation

When working on an issue labeled `copilot-remediate` whose body
includes a finding id (CVE- / GHSA-), follow these rules.

### Scope
- ONE finding per PR. Never bundle multiple advisories.
- Branch: `copilot/<finding-id>`.
- Commit: Conventional Commits: `fix(sec): bump <pkg> from <old>
  to <new> (<finding-id>)`.

### Version bump policy
- Pick the LOWEST version in the advisory's patched range.
- NEVER bump across a major-version boundary. If the only fix
  is a major bump, post a comment on the issue explaining why
  (direct dep vs transitive, breaking changes expected) and
  stop — do not push a PR.
- Pre-release / rc / beta versions are off by default. If the
  advisory lists only a pre-release fix, comment on the issue
  and stop.

### Tooling
- Use the native package manager to apply the bump. Never
  hand-edit the lockfile.
- After the bump, run the lint and test commands documented at
  the top of this file. If they fail because of the bump,
  revert, comment on the issue with the failing tests, and stop.

### Paths you may NOT touch
- `db/migrations/**` — any DB migration.
- `infra/terraform/**` — infra-as-code.
- `**/*.generated.*` — generated code.
- Any CI workflow, except to update a pinned action version in
  response to a CVE on that action.

### PR shape
- Title: `fix(sec): bump <pkg> to <ver> (<finding-id>)`.
- Body: link the issue (`Closes #NNN`), finding id + link to
  advisory, old → new version, direct vs transitive, test
  command + pass evidence, one-line revert instructions.
- Keep the PR as DRAFT. Never mark ready-for-review. Never
  enable auto-merge.

.github/ISSUE_TEMPLATE/security-remediation-dep.yml

name: Security — Dependency remediation
description: Open a remediation task for a single CVE / GHSA finding.
title: "Remediate: <finding-id> in <package>"
labels: ["copilot-remediate", "security"]
assignees: []
body:
  - type: input
    id: finding_id
    attributes:
      label: Finding id
      description: CVE id, GHSA id, or scanner-assigned id.
      placeholder: CVE-2026-1234
    validations:
      required: true
  - type: input
    id: package
    attributes:
      label: Affected package
      description: Package name (best-effort hint from the scanner).
      placeholder: "@example/unsafe-parser"
    validations:
      required: true
  - type: dropdown
    id: severity
    attributes:
      label: Advisory severity
      options: [critical, high, medium, low]
    validations:
      required: true
  - type: textarea
    id: advisory_url
    attributes:
      label: Advisory link(s)
      description: Paste the GHSA / CVE / NVD URL.
    validations:
      required: true
  - type: textarea
    id: notes
    attributes:
      label: Notes for the agent
      description: Anything the scanner couldn't auto-populate.
      placeholder: |
        - Dependency is transitive via "express@4".
        - Workspace package `apps/web` is the caller.
    validations:
      required: false

Dispatch the validated issue

Creating or labeling the issue does not start the cloud agent. First confirm that the advisory is authoritative, the package is installed, and the issue is in the repository that owns the fix. Then choose one supported mechanism:

  • Manual assignment (recommended): select Copilot from the issue’s assignee list and review the target repository, starting branch, and additional instructions. See GitHub’s issue-assignment workflow.
  • API assignment after validation: assign copilot-swe-agent[bot] and send the supported agent_assignment object. The API is a public preview; use GitHub’s current REST or GraphQL contract.
  • Copilot automation only for a trusted intake: eligible private and internal repositories can use an issue-created automation with a narrow search filter and least-privilege tools. Do not connect raw third-party scanner output directly to an autonomous code-writing session. Preserve the default protection against events created by users without write access. See Copilot automations.

The copilot-remediate label is a routing and filter signal only. Do not rely on an assign-copilot.yml Action, an @copilot alias, or assignees: ["copilot"] in the issue template.

Once the session starts, the GitHub Copilot cloud agent reads:

  1. The repo-level copilot-instructions.md (house rules + the dependency addendum above).
  2. The issue body (finding id, package, advisory link).

It produces a draft PR on copilot/<finding-id> that either fixes the finding or posts a comment explaining why the fix was refused (major bump required, pre-release only, tests fail).

Verification

  • Rechecked 2026-08-21 against GitHub’s current Copilot Autofix and Copilot cloud agent (“Assign to Copilot”) workflow.
  • Creating or labeling an issue still does not start the agent; an authorized reviewer must assign the issue after validation.
  • One finding still produces one draft PR or a refusal comment.

Output contract

Return one of:

  • A draft PR linked to the issue that remediates one advisory-driven dependency path, uses the native package manager, touches only allowed manifest/lockfile artifacts, records test evidence, follows branch/commit/title/body rules, and routes to CODEOWNERS review.
  • An issue comment without code changes when the package is not installed, the fix requires a disallowed major bump, only a prerelease exists, tests fail, the scope is ambiguous, or the finding belongs to another repo/workspace.

The output must list finding id, package, advisory link, old/new version, direct/transitive status, files touched, tests/CI evidence, PR URL or refusal reason, and reviewer routing. It must not mark the PR ready, auto-merge, edit forbidden paths, disable tests, or bundle multiple advisories.

Known limitations

  • Instructions are a prompt, not enforcement. Pair this with strict branch protection + CODEOWNERS routing on any path the agent must not touch. The addendum’s “paths you may NOT touch” list is advisory; CODEOWNERS makes it a hard gate.
  • Single-manifest assumption. For monorepos, file one issue per affected workspace so the agent has a narrow scope.
  • Transitive fixes. The agent can only hoist a transitive fix by bumping a parent; if the parent requires a major bump, the addendum forces a stop. That’s the correct behavior, but expect more “refused” comments than raw PRs for older ecosystems.
  • Scanner projection cadence matters. If your scanner projects every low-severity finding into an issue, the Copilot review queue will balloon. Gate projection on severity high | critical and label drift manually.

Changelog

  • 2026-04-21 — v1, first published. Covers Node / Python / Go lockfiles. Major-bump refusal is intentional.