| name | cve-validate |
| description | Validate CVE Jira tickets against the current codebase — assess reachability, exploitability, and recommend action (Go bump vs dependency bump vs code fix) |
| argument-hint | <OSPRH-ticket-id> |
| user-invocable | true |
| allowed-tools | ["Bash","Read","Write","Grep","Glob","WebSearch","WebFetch"] |
| context | fork |
CVE Validation
Validate whether a reported CVE Jira ticket actually affects the current operator codebase, assess how the affected code is used, and recommend the appropriate action.
When invoked (/cve-validate OSPRH-28972), run the full workflow below and produce a structured report.
Prerequisites
You must run this skill from within the operator repository that the CVE is filed against. The skill analyzes the code in the current working directory — if you are in the wrong repo, the results will be meaningless.
Before invoking, ensure:
- Correct repository —
cd into the operator repo that matches the pscomponent: label on the CVE ticket (e.g., osp-director-operator, glance-operator).
- Correct branch — check out the branch the CVE applies to (typically the release branch, e.g.,
v1.3.x, or main). The Go version and dependency versions vary between branches, so the assessment depends on which branch you are on.
- Up-to-date code — run
git pull or git fetch to ensure you are analyzing current code, not a stale checkout.
- Go module present — the directory must contain a
go.mod file.
- Jira MCP available — the Jira MCP server must be configured to fetch ticket details.
Pre-flight check
Before starting the workflow, verify the environment:
test -f go.mod || echo "ERROR: no go.mod — are you in the right directory?"
git remote get-url origin
git branch --show-current
head -3 go.mod
Report the repository name, current branch, and Go version to the user at the top of the output so they can confirm they are analyzing the right target:
Analyzing: github.com/openstack-k8s-operators/osp-director-operator
Branch: v1.3.x
Go: 1.24.4
If go.mod is missing, stop and ask the user to navigate to the correct directory.
Workflow
Step 1: Fetch CVE context from Jira
Use Jira MCP (jira_get_issue) to fetch the ticket with fields: *all.
Extract:
- CVE ID: from the
labels field — look for labels matching CVE-*
- Summary: the ticket summary
- Description: the flaw description — this describes the vulnerable behavior
- Component: from labels matching
pscomponent:*
- Flaw reference: from labels matching
flaw:bz#* or flawuuid:*
From the description, identify the affected Go package or module (e.g., crypto/x509, golang.org/x/net/http2, github.com/golang-jwt/jwt/v5).
If the ticket is not a Vulnerability type or has no CVE label, stop and report:
This ticket is not a CVE vulnerability tracker. Type: <actual type>, Labels: <labels>
Step 2: Classify the affected package
Determine whether the CVE affects:
- Go stdlib — package path has no dots (e.g.,
crypto/tls, net/http, encoding/xml). Fix comes with a Go toolchain bump.
- Direct dependency — listed in
go.mod under require. Fix requires bumping the dependency version.
- Transitive dependency — not in
go.mod directly but pulled in via another dependency. Check go.sum or run grep in go.mod for indirect dependencies.
- Not present — the module is not in
go.mod or go.sum at all. The CVE does not apply.
For Go stdlib CVEs, read the go directive from go.mod to get the current Go version.
For dependency CVEs, find the current version from go.mod:
grep '<module-path>' go.mod
Step 3: Look up CVE details and fix versions
Use WebSearch to search for the CVE ID. Gather:
- What the vulnerability is — a plain-language description of the flaw
- How an attacker exploits it — what input or action triggers the vulnerability (e.g., "send a TLS ClientHello with a crafted certificate chain containing thousands of intermediate certificates")
- What the impact is — DoS, RCE, information disclosure, privilege escalation, etc.
- Which versions contain the fix — for Go stdlib: which Go release(s) include the patch; for dependencies: the minimum fixed version
Compare the fix version against the current version from Step 2.
If the current version already includes the fix, stop and report:
CVE-YYYY-NNNNN is already fixed in the current version (<current>) which is >= fix version (<fix>).
No action required.
Step 4: Discover all build targets in the repository
A single repository can produce multiple container images, each built from different source directories. The CVE ticket's pscomponent: label refers to a specific image, but all images built from this repo share the same go.mod and must all be checked.
Discover all build targets:
find . -name 'Dockerfile*' -not -path '*/CI_TOOLS_REPO/*' -not -path '*/.git/*'
For each Dockerfile found, identify:
- What Go source it builds — look for
go build commands and their target path (e.g., go build -o manager main.go, go build -o agent ./containers/agent).
- Whether it builds Go code at all — some images are shell-script-only or use pre-built binaries (e.g., an image downloader that just installs
qemu-img). Skip non-Go images.
Report all discovered build targets in the output. Example for a repo that builds multiple images:
### Build Targets
| Image | Dockerfile | Go Source | Go Code? |
|-------|-----------|-----------|----------|
| <operator-name> | Dockerfile | main.go | Yes |
| <operator-name>-agent | Dockerfile.agent | ./containers/agent | Yes |
| <operator-name>-downloader | containers/image_downloader/Dockerfile | N/A (shell script) | No |
Many repos build only a single image (one Dockerfile, one main.go). That is fine — just list the single target. The point is to discover and report all of them.
All subsequent steps (searching for imports, analyzing usage) must cover every Go build target, not just the top-level operator code. Scan the entire repo's Go source (all directories), but report findings grouped by build target so it is clear which image is or is not affected.
Step 5: Search codebase and dependency graph for usage
5a. Direct imports in all Go source
Search for imports of the affected package across the entire repository (all build targets):
grep -rn '<package-path>' --include='*.go' . | grep -v vendor/ | grep -v '_test.go'
Also search test files separately (lower risk but worth noting):
grep -rn '<package-path>' --include='*.go' . | grep -v vendor/ | grep '_test.go'
Group findings by build target (e.g., "operator: main.go:22", "agent: containers/agent/main.go:5").
5b. Go module dependency graph
For non-stdlib packages, check whether the affected module appears anywhere in the dependency graph, even if not imported directly by operator code:
go mod graph 2>/dev/null | grep '<module-path>'
If go mod graph is not available (no Go toolchain), fall back to checking go.sum:
grep '<module-path>' go.sum
This reveals transitive dependencies that pull in the vulnerable module. Record which direct dependency pulls it in — this matters for determining the upgrade path.
5c. Transitive stdlib usage
For Go stdlib packages (crypto/tls, net/http, encoding/xml, etc.), the dependency graph check does not apply since stdlib packages are part of the Go toolchain. Instead, consider which framework dependencies are known to use the affected stdlib package and how:
crypto/tls — used by controller-runtime (webhook server, metrics server), client-go (API server connections), any HTTP client/server in dependencies
net/http — used by virtually every dependency that makes or serves HTTP requests
encoding/xml — used by specific XML-processing libraries
For each known transitive usage, assess whether the framework's usage pattern matches the vulnerable code path. For example, client-go uses crypto/tls as a TLS client connecting to the API server — this is a different code path than a TLS server verifying client certificates.
5d. Decision
- No direct imports AND no transitive path to vulnerable code — likely not affected, but proceed to Step 6 for confirmation
- Direct imports found — record each file and line number, proceed to Step 6
- Only transitive usage — note which dependency brings it in and how, proceed to Step 6
Step 6: Analyze usage context
For each file that uses the affected package, read the relevant code and assess. Do this for every build target that has Go code, not just the main operator.
6a. What function/type from the package is used?
Map the actual usage to the CVE's vulnerable function or behavior. For example:
- CVE says
x509.Certificate.Verify is vulnerable — does the code call Verify? Or just MarshalPKCS1PrivateKey?
- CVE says
http2 framing is vulnerable — does the code serve HTTP/2? Or only HTTP/1.1?
If the specific vulnerable function/pattern is not used, the code is not on the vulnerable path.
6b. Is the code reachable by external input?
Assess the attack surface:
- Webhook server — reachable by the Kubernetes API server (cluster-internal, authenticated). The API server initiates TLS connections to the webhook. An attacker would need to compromise the API server or its certificate chain.
- Metrics endpoint — typically reachable by Prometheus within the cluster. Not exposed externally.
- Controller reconciliation — triggered by Kubernetes resource changes. Not directly user-facing.
- CLI/agent code — runs as a pod, processes data from Kubernetes resources or OpenStack APIs.
- SSH/crypto utilities — used for key generation, not certificate verification.
6c. Can an attacker control the vulnerable input?
The key question: can an external actor supply the specific input that triggers the vulnerability?
- For certificate chain CVEs: who provides the certificates? If only the cluster CA (controlled by the admin), the risk is low.
- For HTTP parsing CVEs: who sends the HTTP requests? If only internal Kubernetes components, the risk is lower than public-facing endpoints.
- For XML/JSON parsing CVEs: where does the parsed data come from? User-supplied CRs vs internal system data.
Step 7: Produce report
The report must be formatted in markdown so it can be copy/pasted directly into a Jira Cloud comment. Jira Cloud's rich text editor accepts markdown paste and renders headings, tables, bold, links, and code spans.
- Start the comment with
[AI-GENERATED] prefix as required by project conventions.
- Use markdown headings (
##, ###), markdown tables, **bold**, `code`, and [text](url) links.
- Do not duplicate information. Each table field appears exactly once. Do not repeat version/fix information that is already in the Affected Package table elsewhere in the report.
- Keep the report inside a single markdown fenced code block (
```markdown ... ```) so the user can copy the whole block at once.
After printing the report, ask the user if they want the report written to a local file for easier copy/paste into Jira (avoids trailing spaces from terminal output). Suggest a filename like /tmp/cve-<CVE-ID>-<ticket>.md (e.g., /tmp/cve-2026-32280-OSPRH-28972.md). If the user confirms, write the markdown content (without the surrounding fenced code block delimiters) to that file.
Output the following structured report:
```markdown
[AI-GENERATED] CVE Validation Report
## CVE Validation Report
| Field | Value |
|-------|-------|
| Ticket | <OSPRH-XXXXX> |
| CVE | <CVE-YYYY-NNNNN> |
| Summary | <one-line from Jira> |
| Component | <pscomponent label value> |
| Repository | <module path from go.mod> |
| Branch | <current branch> |
### Vulnerability Description
<2-3 sentence plain-language description of the CVE. Explain what the flaw is, NOT just which package it is in.>
**How an attacker exploits this:** <Concrete description of the attack vector. What does the attacker send, to what endpoint, and what happens? e.g., "An attacker sends a TLS ClientHello that triggers certificate chain verification against a pool containing thousands of crafted intermediate certificates. The verification algorithm has exponential complexity in the number of candidate parents, causing the server to consume excessive CPU and become unresponsive.">
**Impact:** <DoS / RCE / information disclosure / privilege escalation / etc.>
### Affected Package
| Field | Value |
|-------|-------|
| Package | `<e.g., crypto/x509>` |
| Type | Go stdlib / Direct dependency / Transitive dependency |
| Current version | <Go version or dependency version from go.mod> |
| Fix version | <version that patches the CVE, from web search> |
| Fix included in current version | Yes / No — <"Current version X.Y.Z >= fix version A.B.C" or "Current version X.Y.Z < fix version A.B.C"> |
### Build Targets
| Image | Dockerfile | Go Source | Go Code? |
|-------|-----------|-----------|----------|
| <image-name> | <Dockerfile path> | <Go build target> | Yes/No |
<Include all images built from this repo. Non-Go images can be noted but skipped for code analysis.>
### Codebase Usage
<Group findings by build target.>
| Build Target | File | Line | Function/Usage | Vulnerable Path? |
|-------------|------|------|----------------|-------------------|
| operator | main.go | 22 | tls.Config for webhook server | No -- server-side TLS, no client cert verification |
| pkg/common/ssh.go | 48 | x509.MarshalPKCS1PrivateKey | No -- key marshaling, not chain verification |
If no direct usage found:
> The operator does not import `<package>` directly. The package is used
> transitively by <framework/dependency>. Transitive usage is <assessment>.
### Dependency Graph
<If relevant, show which dependencies pull in the affected module and whether their usage is on a vulnerable path. For stdlib CVEs, note which framework components use the stdlib package and how.>
### Risk Assessment
| Criterion | Assessment |
|-----------|------------|
| Reachable | Yes/No -- <how the affected code path can be reached> |
| Attack surface | <who can reach it: cluster-internal only, external users, requires cluster admin> |
| Exploitability | <how likely given the specific usage pattern> |
| Priority | Not Affected / Low / Medium / High / Critical |
```
Priority guidelines (do not include these in the output — use them to determine the priority):
- Not Affected: The vulnerable function/pattern is not used at all — the package may be imported but only for unrelated functionality (e.g.,
x509.MarshalPKCS1PrivateKey when the CVE is about x509.Certificate.Verify). Close the ticket as not affected.
- Low: The vulnerable function is used only in tests, or only transitively via framework code with no direct exposure and no way for external input to reach it.
- Medium: Vulnerable function is used but only reachable by privileged internal components (API server, Prometheus).
- High: Vulnerable function is used, reachable but behind authentication or cluster-internal.
- Critical: Vulnerable function is directly used, reachable by external/untrusted input, no authentication required.
Continue the report inside the same markdown code block:
```markdown
### Verdict
**<ONE OF THE VERDICTS BELOW>**
<1-2 sentence justification summarizing why this verdict was chosen.>
<If NOT AFFECTED, include the following line. Omit for AFFECTED verdicts.>
**Jira action:** Close as "notabug". Set VEX Justification to "Vulnerable code not in execute path".
### Sources
- [CVE entry](<NVD or Go vuln DB URL>)
- [Fix commit/release](<URL>)
- [Bugzilla](<URL if available>)
```
Use one of these verdicts:
-
NOT AFFECTED -- close the ticket as "notabug". The operator does not use the vulnerable code path. The package may be imported but the specific vulnerable function/pattern is not called, or the code is not reachable in a way that triggers the vulnerability. No action is needed -- not even waiting for a Go bump. When closing, set the VEX Justification field to "Vulnerable code not in execute path". Include this instruction in the verdict section of the report so the person closing the ticket knows what to set.
-
AFFECTED -- will be fixed by Go toolchain bump to . The vulnerable code path IS used (directly or transitively in a reachable way), but no code change is needed in this repo. The fix will come when the container image is rebuilt with Go >= .
-
AFFECTED -- dependency bump required. Bump <module> to >= <version> in go.mod. Check if dependabot is pinned below the fix version.
-
AFFECTED -- code change required. The vulnerable pattern is used and must be refactored. Describe specifically what needs to change.
Important distinction: "The package is imported" is NOT the same as "the vulnerable code path is used." If the operator imports crypto/x509 but only uses MarshalPKCS1PrivateKey, and the CVE is about Certificate.Verify, the verdict is NOT AFFECTED. Do not recommend waiting for a Go bump when the code is not affected — that creates unnecessary tracking overhead.
Handling multiple CVEs
If the user provides multiple ticket IDs (/cve-validate OSPRH-28972 OSPRH-29001), process each one sequentially and produce a separate report for each. Add a summary table at the end:
## Summary
| Ticket | CVE | Package | Verdict | Action |
|--------|-----|---------|---------|--------|
| OSPRH-28972 | CVE-2026-32280 | crypto/x509 | Not Affected | Close ticket |
| OSPRH-29001 | CVE-2026-XXXXX | ... | ... | ... |
Examples
Not affected — vulnerable function not used
/cve-validate OSPRH-28972
Expected: crypto/x509 is imported but only for MarshalPKCS1PrivateKey (key marshaling). The CVE is about Certificate.Verify with large intermediates pools — that function is never called. Webhook TLS is server-side only, no client cert verification. Verdict: NOT AFFECTED — close the ticket.
Affected — Go stdlib, needs Go bump
/cve-validate OSPRH-XXXXX
If the CVE affects e.g., net/http request smuggling and the operator runs an HTTP server that parses external requests using the vulnerable pattern, the vulnerable code path is reachable. Verdict: AFFECTED — will be fixed by Go toolchain bump.
Affected — direct dependency needs bump
/cve-validate OSPRH-XXXXX
If the CVE affects e.g., golang.org/x/crypto and the operator imports and uses the specific vulnerable sub-package/function, check the current pinned version and recommend bumping. Verdict: AFFECTED — dependency bump required.