cve-remediation

작성자: microsoft

종속성 매니페스트를 알려진 CVE와 대조해 스캔하고, 취약한 종속성을 패치된 버전으로 업그레이드하여 수정한 다음, 재빌드하고 재스캔하여 확인합니다.…

npx skills add https://github.com/microsoft/github-copilot-modernization --skill cve-remediation

CVE Remediation

This skill is the implementer-owned scan→fix→verify loop for dependency CVEs. It is dispatched as an execute-phase task to an implementer role (backend), runs per group, and produces patched dependency manifests plus an audit trail.

Ownership & boundaries

  • This is implementer work, not audit work. The security role audits and escalates but does NOT fix. This skill performs the fix (editing dependency manifests), so it is owned by the implementer who owns those manifests — not by the security role.
  • The rebuild/re-scan is a self-check, not a quality gate. It is the implementer confirming their own change took — analogous to compiling after editing code. It must NOT masquerade as the project's security gate, and it stays within the Implementation phase label. The independent gates (smoke-test, runtime-validation, and the coordinator's verdict rules) remain separate and unchanged.
  • Scope is per-group. Each in-scope group has its own dependency manifests; remediate the manifests belonging to the dispatched group.

Scanning: tool-first with LLM fallback

CVE scanning is performed by the shared appmod-cve-assessment tool, which all modernization surfaces (VS Code extension, IntelliJ plugin, Copilot CLI plugin, MCP server) expose. It queries the GitHub Security Advisories API for a set of package ecosystems and writes structured findings to a result file. Using the shared tool keeps scanning consistent across products and emits the standard telemetry.

  • Primary — appmod-cve-assessment tool (preferred whenever it applies). Consult the tool's own ecosystem parameter for the ecosystems it currently accepts — treat that schema as the source of truth rather than assuming a fixed list, since it may grow over time.

  • Fallback — LLM-only scan when the tool path does not apply. This covers two cases, both signalled by the tool itself:

    1. Tool unavailableappmod-cve-assessment is not registered in the current runtime (e.g. a standalone Copilot CLI / rearchitecture runtime without the tool wired up).
    2. Ecosystem not accepted — the tool rejects the project's ecosystem (its ecosystem parameter does not accept it / input validation fails). Whichever ecosystems the tool does not yet cover fall here automatically.

    In either case the model identifies known CVEs for the listed dependency versions from its own knowledge and writes the same findings schema (see Step 3). This is best-effort — model knowledge has a training cutoff and may miss recent advisories — so prefer the tool whenever it applies.

Map the project's package manager to the ecosystem identifier the tool accepts (for example, Maven and Gradle both resolve to the same JVM identifier). If the tool does not accept any identifier for the project's ecosystem, go straight to the LLM-only fallback.

Artifact path

The coordinator provides an artifact path for this task. Throughout this skill, {{ARTIFACT_PATH}} refers to that directory. Write all reports and the fix summary there.

Workflow

Step 1: Precheck — detect project type and build tool

Before running any build or dependency commands, verify that the required build tool is available.

  1. Detect the project type by examining the group's project root:

    File(s) foundProject typeTool ecosystem id (common mapping)
    pom.xmlMaven (Java)maven
    build.gradle or build.gradle.ktsGradle (Java)maven
    *.sln.NET solutionnuget
    *.csprojC# projectnuget
    packages.configLegacy .NETnuget
    package.jsonNode.js (npm/pnpm/yarn)npm
    any other manifest (e.g. requirements.txt, pyproject.toml, go.mod, Cargo.toml, Gemfile, composer.json)otherwhatever the tool accepts, else LLM-only fallback (Step 2c)

    The ecosystem ids above are the common mappings at the time of writing. The tool's ecosystem parameter is authoritative — if it accepts an identifier for the project's ecosystem, use the tool; otherwise use the LLM-only fallback.

  2. Resolve the build command — prefer project-local wrappers over global tools:

    Project typeCheck order (prefer first match)Fallback
    Maven./mvnw (Unix) or mvnw.cmd (Windows)mvn on PATH
    Gradle./gradlew (Unix) or gradlew.bat (Windows)gradle on PATH
    .NETdotnet --version
    Node.jsnpm / pnpm / yarn (only needed to apply fixes)
  3. If the required tool is not found, stop and report the error. Do not proceed.

Step 2: Scan dependencies against CVE databases

The scan also serves as detection: a clean result (an empty findings array) means the group has no known dependency CVEs and the task exits cheaply.

Step 2a: Collect dependency coordinates and locations

Extract the dependency coordinates for the group, capturing for each one the workspace-relative file path and 1-based line number where it is declared. Prefer resolved versions (which include transitive dependencies — the common source of CVEs) and fall back to manifest-declared versions when a resolver is unavailable.

EcosystemCoordinate formatWhere to read
mavengroupId:artifactId:versionmvn dependency:list / gradle dependencies (resolved), else pom.xml / build.gradle / gradle.properties
nugetPackageName@versiondotnet list package (resolved), else *.csproj / Directory.Packages.props / packages.config
npmpackage-name@version (e.g. express@4.18.2, @angular/core@16.0.0)lockfile (package-lock.json, pnpm-lock.yaml, yarn.lock — resolved, includes transitives), else package.json

These are the common ecosystems and their coordinate formats. For the authoritative coordinate format expected by each ecosystem the tool accepts, consult the tool's dependencies / ecosystem parameter descriptions. For an ecosystem the tool does not accept (LLM-only fallback), use that ecosystem's natural coordinate form (e.g. package==version for Python) read from its manifest or lockfile.

Step 2b: Scan with the appmod-cve-assessment tool (primary)

Call appmod-cve-assessment with:

  • cveResultFilePath — an absolute path of {{ARTIFACT_PATH}}/cve-report-N.json (start at 1, increment each scan to preserve history).
  • ecosystem — the identifier the tool accepts for the project's package ecosystem (see the tool's ecosystem parameter for the accepted values).
  • dependencies — the coordinate array from Step 2a.
  • dependencyLocations{ coordinate, filePath, lineNumber } for each dependency.

The tool fetches CVEs, writes the findings JSON to cveResultFilePath, and returns a summary message. For very large dependency sets, scan in batches, writing each batch to its own numbered report. If the tool is unavailable, or it rejects the ecosystem as not accepted, switch to the LLM-only fallback (Step 2c).

Step 2c: LLM-only scan (fallback — tool unavailable OR ecosystem not accepted)

Use this path when the tool cannot do the scan — either because appmod-cve-assessment is not available in the current runtime, or because the tool does not accept the project's ecosystem (its ecosystem parameter rejects it). Perform the scan from model knowledge instead: for each coordinate + version, identify known CVEs and write the same findings schema (see Step 3) to {{ARTIFACT_PATH}}/cve-report-N.json. Note in the fix summary that the LLM fallback was used (and why), since it is best-effort and may miss recent advisories.

Large projects: if scanning is slow, run it in a background (async) terminal and, while it runs, review and fix vulnerabilities already known from earlier runs. Address any newly discovered issues once it completes.

Step 3: Review the report and identify vulnerable dependencies

Parse the latest cve-report-N.json and examine each finding:

  1. Read the report file and parse the JSON (an array of findings; [] means no CVEs).
  2. Group by severity: critical > high > medium > low.
  3. For each finding note: the affected dependency + current version and the upgrade target — both are in the evidence.explanation (the Affected dependencies and Recommended fix lines) — plus the CVE identifier (id) and name.
  4. Prioritize critical and high severity for immediate remediation.

Report schema (one object per CVE):

[
  {
    "id": "CVE-2022-22965",
    "name": "Spring Framework RCE via Data Binding on JDK 9+",
    "status": "FOUND",
    "category": "CVE",
    "severity": "critical",
    "storyPoint": 1,
    "evidence": {
      "files": ["pom.xml:20"],
      "explanation": "[CVE-2022-22965](https://github.com/advisories/GHSA-36p3-wjmg-h94x): Spring Framework RCE via Data Binding on JDK 9+\n\nSeverity: CRITICAL\n\nAffected dependencies:\n  - org.springframework:spring-core@5.3.9\n\nRecommended fix:\n  - Upgrade org.springframework:spring-core to 5.3.18 or later"
    }
  }
]

A finding whose explanation contains no Recommended fix line has no upstream patch available (unfixable). An empty array ([]) means no known CVEs were found.

Step 4: Update vulnerable dependencies to secure versions

For each vulnerable dependency, update to a secure version (the upgrade target from the Recommended fix line) using the appropriate method.

Fix principles (consistent with the security agent):

  • Direct upgrade, not a framework upgrade. Bump the affected dependency directly to the patched version — no stepping through intermediate versions. CVE remediation is a targeted patch, not a version migration.
  • Respect a pinned target version. If the user's request pins a target version/line for a dependency (e.g. "upgrade Spring Framework to 6.2.18"), remediate within it — a patch bump within that line to clear a CVE is fine. Only when no in-range patch exists do you leave it — record it as a follow-up (Step 7.3) rather than forcing a major jump.
  • Minimal changes. Change only what is needed to clear the CVE. Do not refactor, reformat, or make unrelated edits.
  • Batch related fixes. When a single upgrade clears several CVEs (e.g. a shared BOM/parent), apply it once for all of them.

Java — Maven (pom.xml)

  1. Find the version (may be in <properties>, <dependencyManagement>, or inline <version>).
  2. Update to the patched version (or the latest stable if the patched version is also outdated).
  3. If the version is inherited from a parent POM (e.g. Spring Boot starter parent), update the parent version instead.

Where CVEs hide — check BOM overrides first. Pay special attention to dependencies that explicitly declare a <version> tag overriding a managed BOM (e.g. the Spring Boot dependencies BOM). These inline overrides bypass BOM management and are the most common source of missed CVE vulnerabilities — bumping the BOM/parent version alone will not patch them. Cross-check the <version> tags in each sub-module's pom.xml against the vulnerable dependencies and update the override (or remove it to fall back to the managed version) as needed.

Java — Gradle (build.gradle)

  1. Find the version in build.gradle or gradle.properties.
  2. Update the version string to the patched version.
  3. If using a BOM or platform dependency, update the BOM version.

.NET (csproj)

  1. Find <PackageReference Include="PackageName" Version="X.Y.Z" />.
  2. Update the Version attribute to the patched version.
  3. If versions are managed centrally via Directory.Packages.props, update them there instead.
  4. Alternatively: dotnet add package PackageName --version X.Y.Z.

Node.js — npm / pnpm / yarn (package.json)

  1. Find the version in package.json under dependencies or devDependencies.
  2. Update the range to the patched version (e.g. "^4.17.21"), then regenerate the lockfile so the resolved transitive versions update too:
    • npm: npm install pkg@X.Y.Z (or edit package.json then npm install)
    • pnpm: pnpm add pkg@X.Y.Z (or edit then pnpm install)
    • yarn: yarn add pkg@X.Y.Z (or edit then yarn install)
  3. Transitive dependencies (the common case for npm CVEs) are pulled in by other packages and have no direct entry in package.json. Force a patched version with an override instead of a direct edit:
    • npm: add an "overrides" block ({ "overrides": { "pkg": "X.Y.Z" } })
    • pnpm: add "pnpm": { "overrides": { "pkg": "X.Y.Z" } }
    • yarn (Berry): add a "resolutions" block Then re-run the install command to regenerate the lockfile.

Step 5: Re-scan to confirm issues are resolved (self-check)

Re-run the Step 2 scan and write the output with the next sequential number. Then compare the new report against the previous one and exit the loop when ANY of these hold:

  • Clean — the report is an empty array ([]). Success.
  • Only unfixable CVEs remain — every remaining finding has no Recommended fix line in its explanation (no upstream patch available). Success; record these in the summary as accepted/unfixable.
  • No progress — after a fix attempt the same fixable CVEs persist — compare by CVE id, not by raw count. A fix that resolves the targeted CVE but surfaces a different, newly-disclosed CVE is progress, not a stall: bump to the highest recommended released version and keep going. Treat it as no-progress (and stop) only when the same CVE id keeps reappearing despite a fix, or when the only way forward is a recommended version that is not yet released (no installable artifact) — record those as accepted/stuck in the summary. Stop here rather than looping forever.

Fixable vs. unfixable — important. A CVE is unfixable only when it has no Recommended fix line (no patched version exists upstream). A CVE that requires a major-version upgrade still has a patched version, so it is fixable — leaving it means remediation is incomplete (the No progress / deferred path, surfaced as a Step 7 follow-up), not the Only unfixable success. Treat the run as fully successful only when no fixable CVEs remain. This matches the security agent's rule: do not claim success while patchable CVEs are still outstanding.

Otherwise — if the count dropped but fixable CVEs (those with a Recommended fix) still remain — return to Step 4, fix the newly reported CVEs, and re-scan, incrementing the report number each time. This loop is the implementer's own confirmation — not a separate gate.

Step 6: Build and test after updates

Use the build command resolved in Step 1.

./mvnw clean verify     # Maven
./gradlew clean build   # Gradle
dotnet build && dotnet test   # .NET
npm install && npm test       # Node.js (npm) — use pnpm/yarn equivalents as appropriate

Verify the build completes, existing tests pass, and the app starts (if applicable). If the build fails due to breaking API changes from an upgrade, apply the necessary code fixes and re-run the build. Cap this at 3 fix attempts — if the build still fails, stop, keep the dependency changes that scanned clean, and document the build issue in the summary (Step 7) rather than looping. Keep this within the Implementation phase — it is a build recheck, not a new phase.

Step 7: Document the changes

  1. Write a summary of CVEs fixed (CVE/GHSA ID, dependency + version, patched version, severity, brief description) to {{ARTIFACT_PATH}}/cve-fix-summary.md. Note whether the scan used the appmod-cve-assessment tool or the LLM-only fallback.
  2. Run a final scan and write it as the final report ({{ARTIFACT_PATH}}/final-cve-report.json). All intermediate numbered reports are preserved for audit history.
  3. If any fix requires a major version upgrade (breaking-change risk), record it as a follow-up item in the summary rather than forcing it silently — and surface it to the coordinator so dependent tasks and reviews are aware.

Environment Setup

Prerequisites

  1. Build tool (one of): mvn / mvnw, gradle / gradlew, or dotnet — to apply fixes and rebuild.
  2. Node.js package manager (npm / pnpm / yarn) — only needed to apply Node.js fixes.
  3. GitHub token (optional, recommended for the tool path — raises the GitHub Security Advisories rate limit from 60 to 5000 req/hr): export GITHUB_TOKEN (or GITHUB_PAT). The appmod-cve-assessment tool reads it from the environment when present.

Error Handling

ErrorCauseSolution
appmod-cve-assessment not availableTool not registered in the current runtimeUse the LLM-only fallback (Step 2c)
Tool rejects the ecosystemThe tool does not accept this project's ecosystemUse the LLM-only fallback (Step 2c)
Rate limit / HTTP 403 from the toolToo many advisory API calls without authSet GITHUB_TOKEN / GITHUB_PAT in the environment
Empty / malformed coordinate rejectedWrong coordinate formatmaven: groupId:artifactId:version; nuget: PackageName@version; npm: package-name@version
Maven/Gradle not foundBuild tool not in PATHInstall or ensure the wrapper (mvnw/gradlew) exists
dotnet CLI not found.NET SDK not installedInstall .NET SDK
No supported project files foundUnrecognized project typeEnsure the root has pom.xml, build.gradle, *.sln, *.csproj, packages.config, or package.json

Troubleshooting

List dependencies manually (to build the coordinate list for Step 2a)

# Maven
mvn dependency:list -DoutputFile=deps.txt -q
grep -E "^   [a-zA-Z]" deps.txt | sed 's/^   //' | awk -F: '{print $1":"$2":"$4}' > coordinates.txt

# Gradle
./gradlew dependencies --configuration compileClasspath > deps.txt

# .NET
dotnet list package > deps.txt

# Node.js (npm) — from package-lock.json (lockfileVersion 2/3)
jq -r '.packages | to_entries[] | select(.key|startswith("node_modules/")) | select(.value.version) | "\(.key|sub(".*node_modules/";""))@\(.value.version)"' package-lock.json | sort -u > coordinates.txt

Feed the resulting coordinates (with their file/line locations) into the appmod-cve-assessment tool, or — when the tool is unavailable — into the LLM-only fallback scan.

Rate limit errors

Set a GitHub token in the environment so the tool authenticates its advisory API calls:

export GITHUB_TOKEN=$(gh auth token)

microsoft의 다른 스킬

oss-growth
microsoft
OSS 성장 해커 페르소나
agent-framework-azure-ai-py
microsoft
Microsoft Agent Framework Python SDK(agent-framework-azure-ai)를 사용하여 Azure AI Foundry 에이전트를 구축합니다. AzureAIAgentsProvider로 지속적 에이전트를 만들 때, 호스팅 도구(코드 인터프리터, 파일 검색, 웹 검색)를 사용할 때, MCP 서버를 통합할 때, 대화 스레드를 관리할 때, 또는 스트리밍 응답을 구현할 때 사용합니다. 함수 도구, 구조화된 출력, 다중 도구 에이전트를 다룹니다.
development
airunway-aks-setup
microsoft
Set up AI Runway on AKS — from bare cluster to running model. Covers cluster verification, controller install, GPU assessment, provider setup, and first deployment. WHEN: "setup AI Runway", "onboard AKS cluster", "install AI Runway", "airunway setup", "deploy model to AKS", "GPU inference on AKS", "KAITO setup on AKS", "run LLM on AKS", "vLLM on AKS", "set up model serving on AKS", "AI Runway controller".
devops
appinsights-instrumentation
microsoft
Azure Application Insights로 웹앱을 계측하기 위한 지침입니다. 원격 분석 패턴, SDK 설정, 구성 참조를 제공합니다. WHEN: 앱 계측 방법, App Insights SDK, 원격 분석 패턴, App Insights란 무엇인가, Application Insights 지침, 계측 예시, APM 모범 사례.
devops
applicationinsights-web-ts
microsoft
브라우저/웹 앱을 Application Insights JavaScript SDK(@microsoft/applicationinsights-web)로 계측합니다. Real User Monitoring(RUM) — 페이지 뷰, 클릭, AJAX/fetch 종속성, 예외, 사용자 지정 이벤트, 백엔드 OpenTelemetry 트레이스와 상관관계가 있는 브라우저 측 GenAI 에이전트 트레이스에 사용합니다. SDK Loader Script 및 npm 설정, 프레임워크 확장(React, React Native, Angular), Click Analytics, 텔레메트리 이니셜라이저, 브라우저에서 생성된 에이전트/도구/모델 스팬에 대한 OTel GenAI 의미론적 규칙을 다룹니다.
devops
azure-ai-anomalydetector-java
microsoft
Azure AI Anomaly Detector SDK for Java로 이상 탐지 애플리케이션을 구축하세요. 단변량/다변량 이상 탐지, 시계열 분석 또는 AI 기반 모니터링을 구현할 때 사용하세요.
development
azure-ai-language-conversations-py
microsoft
azure-ai-language-conversations Python SDK를 사용하여 대화형 언어 이해(CLU)를 구현합니다. ConversationAnalysisClient로 대화 의도와 엔터티를 분석하거나, NLP 기능을 구축하거나, 애플리케이션에 언어 이해를 통합할 때 사용합니다.
development
azure-ai-ml-py
microsoft
Azure Machine Learning SDK v2 for Python. ML 작업 영역, 작업, 모델, 데이터 세트, 컴퓨팅 및 파이프라인에 사용합니다. 트리거: "azure-ai-ml", "MLClient", "workspace", "model registry", "training jobs", "datasets".
development