Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions .github/copilot/skills/security-vulnerability-triage/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
name: security-vulnerability-triage
description: >
Analyze, triage, and rescore security vulnerability tickets (CVE, BDSA,
GHSA, Dependabot, security advisory). Use when the user mentions a CVE/BDSA
ID, asks whether the product is impacted by an advisory, asks to rescore a
vulnerability ticket, or needs a Jira analysis comment for a security
finding. Specialized for Java/Maven projects (e.g. MarkLogic ContentPump /
MLCP) with transitive dependency tracing and bytecode reachability analysis.
---

# Security Vulnerability Analysis

A repeatable, human-in-the-loop process for triaging and rescoring security
vulnerability tickets.

## How to invoke

**All you need:** a Jira bug ID (format `MLE-*****`) that references a CVE, BDSA, or GitHub Dependabot alert.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of keep repeating jira bug id in this section, probably ask the user to provide a jira id at first, check whether necessary info is listed in the jira ticket, if not, stop and ask the user.


- **CVE ticket:** Just the Jira bug ID (e.g. `MLE-29365`). The skill will ask before fetching the advisory from NVD.
- **BDSA ticket:** Paste the BDSA text along with the Jira bug ID (BDSAs are private and can't be fetched).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect, we can setup the connection between copilot and BD simply by providing the api token. This skill should ask for the BD api token and make sure to not persist it anywhere

- **Dependabot / GHSA ticket:** Just the Jira bug ID. The skill will fetch the GHSA advisory from GitHub if you confirm, or you can paste it.
- **Multiple tickets:** List the Jira bug IDs (e.g. `MLE-29365, MLE-29366, ...`). The skill processes each one through the full 9-step flow and produces a summary table at the end (`bug ID | verdict | score | status`). Confirmed-impact tickets are flagged prominently in the summary.

The skill always pauses at two points: when advisory text is missing, and before posting the draft Jira comment.

## Ground rules (must always hold)

1. **Never infer the vulnerable component from a CVE ID, score, or web-search summary.** Read the actual advisory text (Black Duck, NVD, GHSA) before making any claim.
2. **Never assume the CVE↔BDSA mapping.** Confirm from the advisory itself.
3. **Never use "language binding" as an exclusion unless the advisory explicitly names the affected binding** (e.g. "Node.js only", "Swift only"). Otherwise treat as cross-language.
4. **"On the classpath" ≠ "used at runtime".** Confirm reachability with source search *and* bytecode inspection (`javap -c`).
5. **Never post a Jira analysis comment without explicit user approval.**
6. **Always verify Jira field updates with a follow-up GET.** The API returns 200 OK even when custom fields silently fail to save (Agile Team, cascading selects, Fix Version by name, Sprint as object). Confirm fields actually persisted before transitioning status.
7. **Only run on security vulnerability tickets.** Verify in step 1 that the ticket is actually a CVE / BDSA / GHSA / Dependabot bug (via component, labels, title prefix, or advisory ID in the description). If it isn't, stop and tell the user — don't try to fit a non-security ticket through this workflow.

## The 9-step process

Follow these steps in order. Do not skip steps.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which step recalculates the cvss score?


### 1. Gather the ticket
Fetch the ticket with `mcp-atlassian-jira_get_issue` and **verify it's a security vulnerability ticket** before doing anything else. Signals to look for:
- Component is `Security`, or label includes `Security` / `CVE` / `BDSA`
- Title contains `[CVE]`, `[BDSA]`, `[GHSA]`, or a CVE/BDSA/GHSA ID
- Description references a CVE / BDSA / GHSA ID or a Dependabot alert
- A CVSS score field is set

If **none** of these match, stop and tell the user the ticket doesn't look like a security vulnerability and the skill won't proceed. Do not guess.

If valid, capture: BDSA/CVE/GHSA ID, current CVSS score and severity, affected library + version, project key, component.

### 2. Get the advisory text
Ask the user to paste the Black Duck advisory, or fetch from NVD (`https://nvd.nist.gov/vuln/detail/<CVE-ID>`). **Do not** infer the vulnerable component from the CVE ID alone or from search engine summaries.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the user connect to blackduck using token and copilot get the advisory from blackduck?


### 3. Identify the vulnerable component
From the advisory text, pinpoint exactly what is affected:
- Specific class or file (e.g. `TSSLTransportFactory.java`)
- Language binding (e.g. `c_glib`, Rust impl, Node.js only)
- Specific code path or feature (e.g. "only when SSL is enabled")

### 4. Trace the dependency chain
Find how the vulnerable library enters the product's classpath.
- Check **explicit** deps in `pom.xml` (root and module poms).
- Check **transitive** sources by inspecting direct dependency POMs in the Maven cache (`~/.m2/repository/...`).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does user need to keep cache clean before running this workflow? Or can user specify a different Maven cache folder?

- Run `mvn dependency:tree -Dincludes=<groupId>:<artifactId> -Dverbose` to enumerate every path.
- Verify against the **current version** of each candidate — a dep may have been added years ago for a use case that no longer applies.

**Red flag:** an explicit dependency with no obvious current consumer.

### 5. Analyze reachability
- Source search (`grep`/`glob`) for imports and references.
- For Java: confirm whether the vulnerable class is loaded eagerly (static initializer / class referenced at startup) or lazily (only on specific method invocation). Use `javap -v -c -p -classpath <jar> <FQCN>` and inspect the `static {}` block plus the constant pool.
- If the vulnerable code path is **unreachable**, removing the library silently eliminates it; if eagerly loaded, removal would cause startup failures (signal it's actually used).

### 6. Draft the analysis comment
Use the Jira comment template below. **Always** show the draft to the user for review before posting.

### 7. Review with user
Wait for explicit approval. Never post without it.

### 8. Post the comment
Use `mcp-atlassian-jira_add_comment` with the approved body.

### 9. Update the ticket
- **Title:** append ` - Rescore <N>` (e.g. ` - Rescore 0`).
- **Calculated CVSS field (`customfield_11168`):** update to the rescored value.
- **Priority:** adjust to match rescored severity.
- **Status:** transition to **In Review** (use `mcp-atlassian-jira_get_transitions` then `mcp-atlassian-jira_transition_issue`).

## Rescoring guidance

| Verdict | Score | When |
|---|---|---|
| Not impacted | 0 | Vulnerable component/code path unreachable, or affected binding not used. |
| Reduced | < advisory | Reachable but mitigated (e.g. only in disabled feature, requires authenticated admin). |
| Confirmed | = advisory | Reachable in default config / typical use. |

State the **basis** for the score in the comment, not just the number.

## Jira analysis comment template

```markdown
**Root Cause — How [library] enters [product]'s classpath**

[Explain how the vulnerable library ends up on the classpath — direct dep,
transitive dep, or both. Name the specific dependency chain.]

---

**Impact Analysis**

[Name the CVE/BDSA and the specific vulnerable component (class, file, or
binding) it affects.]

[Lead with what the product does — which code/files use the library and
what operations they perform. Then state whether the vulnerable
component/code path is reachable from the product's usage. If not impacted,
explain why. If impacted, describe the attack surface and preconditions.]

---

**Suggested Fix**

[Concrete change — upgrade to fixed version, remove dep, add exclusion,
apply workaround, or "no action required — code path unreachable".]

---

**Rescore Justification — <score> (<verdict>)**

[Final conclusion: whether the vulnerable component is reachable, what the
real-world risk is, and the basis for the score assigned.]
```

### Comment style notes

- Lead each section with the **conclusion**, then the evidence.
- Cite specific class names, file paths, and method names — not generalities.
- Quote relevant POM snippets and `javap` output when they materially support the conclusion.
- Avoid excessive bold formatting; plain prose reads better in Jira.

## Lessons learned (case studies)

### The libthrift transitive trap
During the Apache Thrift BDSA batch (MLE-29365–29372), libthrift was first attributed to Hadoop YARN, but Hadoop 3.x had dropped Thrift entirely. The actual transitive source was Apache Jena 4.9.0 (`jena-arq`), used only for RDF/Thrift serialization — a path MLCP never invokes. Stopping at the first plausible attribution would have produced a fix recommendation that did nothing. Always verify against the **current** POM of every candidate, not its history.

### BDSA score doesn't mean BDSA scope
CVE-2026-41636, CVE-2026-41604, and BDSA-2026-9090 all carried 7.9 High CVSS scores against Apache Thrift. The advisory text revealed they affected Node.js and Swift bindings only — Java was unaffected. Without reading the actual advisory, every row would have looked like a critical Java vulnerability.

### Eager vs lazy class loading
Source-grep proved Jena imports libthrift, but that didn't prove the code was reachable. Running `javap -c -p` showed libthrift classes were only referenced inside method bodies, never in a `static {}` block — so removing libthrift would not cause a JVM startup failure. Source search proves intent; bytecode proves behavior.

### Jira API silently accepts wrong field formats
On step 9 updates, several silent failures occurred: Agile Team set as `[{"name": "MLE-Light"}]` (wrong; needs `["MLE-Light"]`), cascading Product-Module missing child value, Fix Version set by name instead of ID. Jira returned 200 OK each time but the fields stayed blank. Always GET-after-PUT before transitioning status.

### BDSA may bundle multiple CVE years
BDSA-2026-8506 mapped to CVE-2025-48431 — a 2025 CVE inside a 2026 BDSA. The BDSA year reflects when Black Duck issued the advisory, not when the CVE was published. The BDSA ↔ CVE mapping must come from the advisory text, not from pattern-matching IDs.

### Never post a comment without explicit review
On one ticket in the Thrift batch, an incorrect Product-Module value was written before user review and then had to be corrected across all 8 tickets. The cost of a quick review is seconds; the cost of a Jira correction across N tickets compounds. Always show the draft to the user first.
Loading