VEX (Vulnerability Exploitability eXchange) capability#2038
Conversation
Add implementation plan, validation spec, and source issue details for VEX Workflow (microsoft#1220) and VEX Generation Agent (microsoft#1221). - 7-phase plan with dependency graph and deliverables - 100+ checkable validation criteria - Issue details with WilliamBerryiii's technical review comments - README with usage instructions for distributing work
Add OpenVEX document, CODEOWNERS entry, PR template, spelling dictionary updates, VEX standards instructions, and release pipeline attestation and upload for VEX artifacts. - Create security/vex/hve-core.openvex.json with product identity - Add /security/vex/ to CODEOWNERS - Create vex-triage.md PR template with confidence bands - Add openvex and osv to cspell dictionary - Create vex-standards.instructions.md with 5-band routing - Extend attest-and-upload and upload-plugin-packages jobs - Add VEX verification section to release notes
Restructure the VEX triage PR template with a repeatable per-CVE assessment block containing status, confidence band, and impact statement fields. Move evidence checklist to a shared top-level section and add a summary field.
- introduce VEX generation instructions - add CVE data sources and licensing guidance - include OpenVEX JSON schema reference - implement VEX status logic for triage 📜 - Generated by Copilot
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…sary peer flags in package-lock.json
…e and licensing clarity
…nVEX schema, and VEX status logic documents
…nstructions - mark skill and generation instructions as complete - validate YAML frontmatter and references - ensure automated checks pass
Co-authored-by: JasonTheDeveloper <jagoodse@microsoft.com>
Co-authored-by: JasonTheDeveloper <jagoodse@microsoft.com>
Co-authored-by: JasonTheDeveloper <jagoodse@microsoft.com>
Co-authored-by: JasonTheDeveloper <jagoodse@microsoft.com>
style: remove duplicate Copilot note from CVE data sources 🔧 - Generated by Copilot
…e evidence recording
…nce routing rules - merge evidence requirements and confidence-routing sections for clarity - streamline agent behavioral rules for better understanding - remove redundant details while maintaining essential information
- specify that preferring OSV.dev does not bypass GHSA licensing - update evidence requirements for reachability determination
…nstructions - set timestamp only on first issuance - update last_updated to current generation time
…cords 🔒 - Generated by Copilot
feat(openvex-spec): add OpenVEX specification and supporting documents
- introduce vex-overview.md for a comprehensive explanation of VEX capability - outline the problem VEX solves and the two complementary tracks - detail the end-to-end flow and safety guardrails for implementation 🔒 - Generated by Copilot
# Conflicts: # .github/workflows/release-stable.yml
- align vex-standards to canonical openvex-spec skill, fix vendor-disputed band - add OpenVEX version field and document mutation contract - de-duplicate VEX release upload into a single non-matrix job - exclude PR template dir from frontmatter lint; cspell and wording fixes 🔒 - Generated by Copilot
- allow foundation/bootstrap VEX docs to ship empty statements in schema reference - mark superseded vendor-disputed routing in planning doc audit trail - correct licensing table column padding 🔒 - Generated by Copilot
feat(workflows): Phase 1 - VEX Foundation (Plumbing)
- vex-generator orchestrator: scan, enrich, delegate, assemble OpenVEX - cve-analyzer subagent: per-CVE reachability analysis, read-only - both reference the canonical openvex-spec skill rather than duplicating Implements #3 🔒 - Generated by Copilot
- add todos to orchestrator tools and use it to track the CVE batch in Phase 3 - subagent stays read-only and minimal (no todos) 🔒 - Generated by Copilot
|
Implementation tracking epic (on the contributor fork): dasiths/hve-core#10 — breaks the work into the eight delivered phases across the workflow and tooling tracks, with per-phase PRs and the live end-to-end drafting-workflow validation run. All CI checks on this PR are currently green (table-format and |
Updates the architecture docs to reflect the VEX capability merged in PR #25, which the Documentation Update Check workflow flagged as stale. workflows.md: - Add vex-detect.yml to the Workflow Inventory. - Cross-reference the vex-draft.md agentic workflow. - Add attest-and-upload-vex and append-verification-notes to the Main Branch Pipeline diagram and jobs table; correct publish-release and upload-plugin-packages dependencies. agentic-workflows.md: - Count six event-driven workflows (was five). - Add VEX Draft to the Workflow Details and Workflow Configuration tables and to the automated-pipeline flowchart. Closes #26 Closes #27 Closes #28
docs(architecture): document VEX workflows and release attestation
bindsi
left a comment
There was a problem hiding this comment.
Approved: the VEX detection workflow is scoped with appropriate permissions and robust handling of OSV/OpenVEX data. I did not find actionable issues.
katriendg
left a comment
There was a problem hiding this comment.
Thanks @dasiths, I really appreciate the depth of thinking and iteration that went into this. It clearly builds on the prior discussions we've been having offline, the iterations you've done, the care in validating some of the harder aspects of this space, especially around non‑determinism, validation, and end-to-end workflow design.
The way you've structured the draft-and-merge accountability model, introduced the human-in-the-loop validation, and handled the forbidden-transition guard all give a lot of confidence that this isn't just a conceptual experiment, but something that's been exercised with real care. The licensing posture across OSV/NVD/GHSA and the release-time Sigstore attestation are also exactly in line with the direction we want to go.
I also really value the effort you've put into actually validating the pipeline — the live gh-aw drafting run makes a big difference in demonstrating that this holds together in practice. Shipping this in experimental maturity and learning from the initial runs within HVE Core ourselves, and with the AW workflow, feels like the right and responsible call given where we are.
My feedback is mostly about hardening the trust story before we lean on this, not about the core design. Leaving some inline comments below, plus a few general items.
- Correctness/completeness: I'd like an eval loop / labeled CVE corpus before we trust
not_affectedat scale. The repo now has first-class eval support, so let's track that as a post-merge backlog issue and make it the gate for promotion tostable. - Human-in-the-loop: love the pattern; let's make the CODEOWNERS gate enforced (branch protection) rather than convention, and close out the autonomous-PR-identity follow-up so drafted PRs trigger required checks.
- RAI/limitations: the AI-generated disclaimer is well covered in the docs; one small gap is embedding provenance in the published JSON itself.
- A couple of convention nits inline (skill-by-name references).
Track eval coverage with a post-merge backlog issue
This capability has no eval coverage yet, and the repo now has first-class support for evals that new AI artifacts are expected to wire up — see docs/contributing/evals-ci.md and the "Adding New Evals" section in evals/README.md. Given the known variability in LLM outputs and the multi-step reachability reasoning here, please open a post-merge backlog / tracking issue to add a vally eval suite for the VEX agents before this leaves experimental. Concretely: an evals/agent-behavior/ (and/or skill-quality) suite with a labeled CVE corpus (known reachable vs. unreachable cases) that asserts the forbidden-transition guard and measures the not_affected false-positive rate, using the copilot-sdk executor with runs: 3+. That eval becomes the machine-checkable gate for the documented promotion criteria (≤5% FP on not_affected across 3+ codebases). Landing as experimental now is fine; the eval issue should be tracked as the promotion blocker.
Enforce the human-in-the-loop gate
The draft-and-merge model and forbidden-transition guard are excellent. Two reinforcements so the human gate is enforced rather than conventional: (a) add branch protection requiring CODEOWNERS review on /security/vex/** (the CODEOWNERS entry is in place, but review enforcement needs the branch rule); (b) resolve the open autonomous-PR-identity follow-up (the GH_AW_GITHUB_TOKEN / GitHub App seam) so drafted PRs trigger required downstream checks — a PR authored by the default GITHUB_TOKEN may not.
Source provenance / licensing confirmation
The openvex-spec skill frontmatter lists metadata.skill_based_on: https://github.com/dasiths/ai_generated_vex (a personal repo). This may not be something we want to keep, regarding licensing and supportability — do we really need it, since you're the git contributor for the PR anyway? Everything else on licensing (OpenVEX Apache-2.0/CC0, NVD public domain, GHSA URL-only) looks well-handled.
Embed AI-assisted provenance in the published JSON
The AI-generated/human-reviewed disclaimer is well covered in vex-verification.md and the agent docs. One gap: a consumer reading the raw hve-core.openvex.json outside the docs sees no provenance marker. Consider a documented convention (a doc-level field or per-statement status_notes) recording that statements are AI-drafted and human-reviewed.
Broader supply-chain integration (optional)
Integration is strong at the release/attestation layer (SC-9, SBOM pairing, SECURITY.md). VEX isn't yet referenced from the supply-chain-security skill or sssc-planner instructions, though — since VEX is a natural extension of the SBOM/Scorecard/SLSA story, wiring it in there would be a logical follow-up. Worth considering a backlog item to keep track of that.
| * #file:../../skills/security/openvex-spec/SKILL.md — OpenVEX v0.2.0 schema, status definitions, justification codes, and document structure. | ||
| * #file:../../skills/security/openvex-spec/references/vex-status-logic.md — decision tree, evidence requirements, confidence bands, and forbidden transitions. |
There was a problem hiding this comment.
Repo convention is to reference a skill by its name (e.g., the powerpoint skill, the telemetry-foundations shared skill), rather than via a #file: walk-up path into the skills tree — see other agents under .github/agents/. Skill paths into skills/ are also more fragile across distributed contexts. The instruction references via relative #file: paths (Lines 35–36) are fine and can stay.
| * #file:../../skills/security/openvex-spec/SKILL.md — OpenVEX v0.2.0 schema, status definitions, justification codes, and document structure. | |
| * #file:../../skills/security/openvex-spec/references/vex-status-logic.md — decision tree, evidence requirements, confidence bands, and forbidden transitions. | |
| * Use the skill `openvex-spec` for OpenVEX v0.2.0 schema, status definitions, justification codes, and document structure. | |
| * Use the file `references/vex-status-logic.md` from the `openvex-spec` skill for decision tree, evidence requirements, confidence bands, and forbidden transitions. |
There was a problem hiding this comment.
Done in e935ec9 — the agent now references the openvex-spec skill and its references/vex-status-logic.md by name; the instruction #file: references are left as-is per your note. Now included in this PR via the fork's main.
|
|
||
| ## Canonical Rules | ||
|
|
||
| The authoritative decision tree, per-status evidence requirements, justification codes, confidence-routing bands, and forbidden transitions are defined in the `openvex-spec` skill reference #file:../../../skills/security/openvex-spec/references/vex-status-logic.md. Read it in full during setup and follow it exactly. Agent behavioral constraints are defined in #file:../../../instructions/security/vex-generation.instructions.md. Do not duplicate or paraphrase those tables here; treat the skill reference as the single source of truth. |
There was a problem hiding this comment.
Same skill-by-name convention here. The line already names the openvex-spec skill, so just drop the #file: skill path and keep the in-skill reference name. (The instruction #file: path later in the line is fine to leave.)
| The authoritative decision tree, per-status evidence requirements, justification codes, confidence-routing bands, and forbidden transitions are defined in the `openvex-spec` skill reference #file:../../../skills/security/openvex-spec/references/vex-status-logic.md. Read it in full during setup and follow it exactly. Agent behavioral constraints are defined in #file:../../../instructions/security/vex-generation.instructions.md. Do not duplicate or paraphrase those tables here; treat the skill reference as the single source of truth. | |
| The authoritative decision tree, per-status evidence requirements, justification codes, confidence-routing bands, and forbidden transitions are defined in the `openvex-spec` skill reference `references/vex-status-logic.md`. Read it in full during setup and follow it exactly. Agent behavioral constraints are defined in #file:../../../instructions/security/vex-generation.instructions.md. Do not duplicate or paraphrase those tables here; treat the skill reference as the single source of truth. |
There was a problem hiding this comment.
Done in e935ec9 — dropped the #file: skill path; the line now names the in-skill reference references/vex-status-logic.md. The instruction #file: path later in the line is kept.
|
|
||
| ### Pre-requisite: Setup | ||
|
|
||
| 1. Read the canonical skill reference #file:../../../skills/security/openvex-spec/references/vex-status-logic.md end-to-end to load the decision tree, evidence requirements, justification codes, confidence bands, and forbidden transitions. |
There was a problem hiding this comment.
Same fix in the Setup step — reference the openvex-spec skill by name rather than the walk-up path. (Line 45's instruction #file: reference is acceptable as-is.)
| 1. Read the canonical skill reference #file:../../../skills/security/openvex-spec/references/vex-status-logic.md end-to-end to load the decision tree, evidence requirements, justification codes, confidence bands, and forbidden transitions. | |
| 1. Read the `openvex-spec` skill reference `references/vex-status-logic.md` end-to-end to load the decision tree, evidence requirements, justification codes, confidence bands, and forbidden transitions. |
There was a problem hiding this comment.
Done in e935ec9 — the Setup step now reads the openvex-spec skill reference references/vex-status-logic.md by name. Line 45's instruction #file: reference is unchanged.
…ded provenance) Addresses review feedback on microsoft#2038. A (convention nits): reference the openvex-spec skill by name instead of via #file: walk-up paths into the skills tree, in the VEX generator agent and the CVE analyzer subagent. Instruction #file: references are left as-is. B4 (embedded provenance): add the OpenVEX document-level tooling field to the published security/vex/hve-core.openvex.json so provenance (AI-drafted, human-reviewed, Sigstore-attested) lives inside the document, not only in the external attestation. Teach it in the document mutation contract (vex-standards), the OpenVEX JSON output requirements (vex-generation), and the schema example. Bumps the foundation document to version 2.
fix(security): address VEX review feedback (skill-by-name refs, embedded provenance)
|
Thanks for the thorough and generous review, @katriendg. I've pushed a round addressing the actionable items; the commits are now in this PR via the fork's Done in this PR
Deferred to the HVE Core maintainers (post-merge backlog) These are yours to own and prioritise, as you suggested:
I've intentionally not opened these as issues so the core team can scope them in your backlog. Happy to help implement any of them once filed. |
Proposed post-merge plan and backlogConsolidating the follow-ups from the review into one place so we can track them after merge. The skill-by-name nits and B4 (embedded provenance) are already done in this PR; everything below is forward-looking. Post-merge activities (operational setup, one-time)
Backlog items (tracked work / promotion gates)
Already addressed in this PR
@katriendg — does this capture the right set of post-merge activities and backlog items, with sensible owners and sequencing? If anything is missing or you'd reframe a gate, I'll adjust. I've intentionally not opened these as issues so the core team can file/scope them, but I'm happy to draft any of them on request. |
Heads-up: the one red check is a transient infra flake (no action needed on the diff)
That It is unrelated to this PR:
Could a maintainer re-run the failed job (run 27766610829)? I don't have Actions permissions on the upstream repo to re-run it myself. Thanks @katriendg! |
| rows = sorted(findings.values(), key=lambda f: f['id']) | ||
| count = len(rows) | ||
|
|
||
| body_lines = [ | ||
| '## VEX detection: untriaged vulnerabilities', | ||
| '', | ||
| f'OSV-Scanner found **{count}** vulnerability(ies) that are untriaged or carry a ' | ||
| 'non-terminal status in `security/vex/hve-core.openvex.json`. Triage each with ' | ||
| '`/vex-triage` or `/vex-scan` (see the VEX Generator agent), then open a PR using ' | ||
| 'the VEX triage template.', | ||
| '', | ||
| '| Vulnerability | Aliases | Package | Source | Severity | Current VEX status |', | ||
| '|---------------|---------|---------|--------|----------|--------------------|', | ||
| ] | ||
| for f in rows: | ||
| body_lines.append( | ||
| f"| {f['id']} | {f['aliases']} | {f['package']} | {f['source']} | {f['severity']} | {f['status']} |" | ||
| ) | ||
| body_lines += ['', '_Generated by the VEX Detection workflow (OSV-Scanner). This is detection only; no status has been drafted._'] | ||
|
|
||
| with open('/tmp/vex-issue-body.md', 'w', encoding='utf-8') as fh: | ||
| fh.write('\n'.join(body_lines) + '\n') | ||
|
|
||
| with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as fh: | ||
| fh.write(f'count={count}\n') | ||
|
|
||
| print(f'Untriaged findings: {count}') | ||
| PY | ||
|
|
||
| - name: File or update detection issue | ||
| if: ${{ steps.diff.outputs.count != '' && steps.diff.outputs.count != '0' }} | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| REPO_SLUG: ${{ github.repository }} | ||
| ISSUE_TITLE: 'VEX detection: untriaged vulnerabilities found' | ||
| run: | | ||
| existing=$(gh issue list \ | ||
| --repo "${REPO_SLUG}" \ | ||
| --state open \ | ||
| --label automated \ | ||
| --search "in:title \"${ISSUE_TITLE}\"" \ | ||
| --json number,title \ | ||
| --jq "map(select(.title == \"${ISSUE_TITLE}\")) | .[0].number // empty") | ||
| if [[ -z "${existing}" ]]; then | ||
| gh issue create \ | ||
| --repo "${REPO_SLUG}" \ | ||
| --title "${ISSUE_TITLE}" \ | ||
| --label "security,automated,needs-triage" \ | ||
| --body-file /tmp/vex-issue-body.md | ||
| else | ||
| gh issue edit "${existing}" \ | ||
| --repo "${REPO_SLUG}" \ | ||
| --body-file /tmp/vex-issue-body.md | ||
| fi |
There was a problem hiding this comment.
Nitpick: the "File or update detection issue" step is gated on count != '0', so when a later run finds zero untriaged vulnerabilities (all CVEs triaged), any previously opened detection issue is never closed. It stays open indefinitely.
A companion step closes the loop:
- name: Close detection issue when all vulnerabilities are triaged
if: ${{ steps.diff.outputs.count == '0' }}
env:
GH_TOKEN: ${{ github.token }}
REPO_SLUG: ${{ github.repository }}
ISSUE_TITLE: 'VEX detection: untriaged vulnerabilities found'
run: |
existing=$(gh issue list \
--repo "${REPO_SLUG}" \
--state open \
--label automated \
--search "in:title \"${ISSUE_TITLE}\"" \
--json number,title \
--jq "map(select(.title == \"${ISSUE_TITLE}\")) | .[0].number // empty")
if [[ -n "${existing}" ]]; then
gh issue comment "${existing}" \
--repo "${REPO_SLUG}" \
--body "All previously untriaged vulnerabilities have been resolved or suppressed by the VEX document. Closing."
gh issue close "${existing}" \
--repo "${REPO_SLUG}"
fiThere was a problem hiding this comment.
Done in 1c8a741 — added a companion step gated if: count == '0' that finds the open detection issue (same title + automated search the file step uses), comments, and closes it. The two gates are mutually exclusive and no new permissions are needed (issues: write already declared). Now in this PR via the fork's main.
| pass | ||
|
|
||
| findings = {} | ||
| for result in scan.get('results', []): | ||
| source = (result.get('source') or {}).get('path', 'unknown') | ||
| for pkg in result.get('packages', []): | ||
| info = pkg.get('package', {}) or {} | ||
| name = info.get('name', 'unknown') | ||
| version = info.get('version', 'unknown') | ||
| groups = pkg.get('groups', []) or [] | ||
| max_sev = next((g.get('max_severity') for g in groups if g.get('max_severity')), '') | ||
| for vuln in pkg.get('vulnerabilities', []): | ||
| vid = vuln.get('id', 'unknown') | ||
| aliases = vuln.get('aliases') or [] | ||
| all_ids = [vid] + aliases | ||
| vex_status = next((known[i] for i in all_ids if i in known), None) | ||
| # Suppress only vulns with a terminal VEX status; untriaged | ||
| # (no statement) and non-terminal statuses are reported. | ||
| if vex_status in TERMINAL: | ||
| continue | ||
| sev = max_sev | ||
| if not sev: | ||
| for s in vuln.get('severity', []) or []: | ||
| if s.get('score'): | ||
| sev = s['score'] | ||
| break | ||
| findings[vid] = { | ||
| 'id': vid, | ||
| 'aliases': ', '.join(a for a in aliases if a) or '-', | ||
| 'package': f'{name}@{version}', | ||
| 'source': source, | ||
| 'severity': sev or '-', |
There was a problem hiding this comment.
The findings dict is keyed by vulnerability ID. When the same CVE affects multiple packages, each loop iteration overwrites the prior entry, so the detection issue table reflects only the last package encountered for that CVE. VEX triage is per-CVE so correctness is unaffected, but maintainers lose visibility into the full blast radius.
Accumulating affected packages instead preserves that detail:
if vid in findings:
findings[vid]['package'] += f', {name}@{version}'
else:
findings[vid] = {
'id': vid,
'aliases': ', '.join(a for a in aliases if a) or '-',
'package': f'{name}@{version}',
'source': source,
'severity': sev or '-',
'status': vex_status or 'none',
}There was a problem hiding this comment.
Done in 1c8a741 — findings now accumulates all affected packages per CVE (deduped and sorted) instead of overwriting, so the table preserves the full blast radius. Triage stays per-CVE, so VEX status correctness is unchanged. Thanks for the catch!
…ulti-package CVEs Addresses review feedback on microsoft#2038 (@rezatnoMsirhC). - Add a step that closes the dedup detection issue when a later run finds zero untriaged vulnerabilities, so it no longer stays open indefinitely after all CVEs are triaged or suppressed. - Accumulate all affected packages per CVE in the findings table instead of overwriting with the last package, preserving blast-radius visibility. Triage remains per-CVE so VEX correctness is unchanged.
fix(workflows): close VEX detection issue when clear and accumulate multi-package CVEs
|
@rezatnoMsirhC — thanks for the sharp review. Both of your
Replies are on both inline threads. Would you mind taking another look and letting me know if the approach matches what you had in mind? Happy to adjust. (Unrelated heads-up: the two currently-red checks are not from this change — |
# Conflicts: # collections/hve-core-all.collection.md # collections/hve-core-all.collection.yml # collections/security.collection.md # plugins/hve-core-all/README.md # plugins/security/README.md
|
Thanks for the fast turnaround, @dasiths — re-reviewed against the latest head ( I've filed the two deferred follow-ups so they don't get lost:
Two things still open on my side before approval:
@WilliamBerryiii — could you do a pass on this PR and the overall approach, and ack/approve the direction? In particular the draft-and-merge accountability model, the |
# Conflicts: # collections/hve-core-all.collection.md # plugins/hve-core-all/README.md
Remove the metadata.skill_based_on provenance pointer to a personal prototype repo (dasiths/ai_generated_vex) per upstream review. content_based_on already records the genuine OpenVEX spec source. Addresses review feedback on microsoft#2038.
|
Thanks for the thorough re-review, @katriendg, and for the quick turnaround. Much appreciated. Good news: both pre-approval blockers are sorted, and the branch is current with Blocker A (branch conflict): re-synced the fork's Blocker B ( #2133 (human-in-the-loop enforcement): completely agree, this is the heart of the trust model and worth getting right before we lean on it. The #2132 (eval gate): sounds right. Acknowledged as the post-merge (For context, the earlier red checks were both non-content: a transient |
VEX (Vulnerability Exploitability eXchange) capability
Description
Introduce an end-to-end VEX (Vulnerability Exploitability eXchange) capability to HVE Core, enabling machine-readable, signed documentation of per-CVE vulnerability impact and reachability. A scanner reports "you have N CVEs," but most are not exploitable in this product: the vulnerable function is never called, the code path is unreachable, or the dependency is only used at build time. VEX records, per CVE, why a vulnerability does or does not affect HVE Core. It turns scanner noise into accountable answers and lets VEX-aware scanners (Trivy, Grype) suppress findings the maintainers have assessed as
not_affected.The capability spans two complementary tracks that converge on an AI-assisted, human-reviewed drafting loop:
/vex-scan+/vex-triageprompts.The trust model is AI drafts, human merges: the agent performs every step except the merge click; the merge-commit author is the accountable author of record, and the agent is forbidden from asserting
not_affectedat low confidence. The PR also includes extensive validation and a clear licensing posture.The most important changes are:
Workflow and Foundation
security/vex/hve-core.openvex.json) published with each release and attested twice via theattest-and-upload-vexjob inrelease-stable.yml: a build-provenance attestation of the VEX file, and an in-toto attestation that binds the VEX document as the predicate over the dependency SBOM subject (the OpenVEX encapsulating format)..github/workflows/vex-detect.yml) that scans dependencies with OSV-Scanner, diffs findings against the VEX document, and files a single deduplicated triage issue for untriaged or status-drifted CVEs..github/workflows/vex-draft.mdand compiledvex-draft.lock.yml, gh-aw enginecopilot) that opens one pull request with an updated VEX document, ensuring only human-reviewed changes are merged.Tooling and Agent Intelligence
.github/skills/security/openvex-spec/: SKILL, schema, status-logic, and CVE-data-source references) plus thevex-standardsandvex-generationinstructions..github/agents/security/vex-generator.agent.md) and a dedicated CVE Analyzer subagent (.github/agents/security/subagents/cve-analyzer.agent.md) for deep, evidence-based exploitability analysis.GHSA-/PYSEC-for OSV and GitHub,CVE-for NVD) with alias fallback, so records are resolved regardless of which identifier a scanner reports./vex-scanand/vex-triageprompts for interactive triage and evidence collection, with collection registration and a new VEX triage PR template that standardizes evidence requirements and reviewer checklists.Integration and Environment
.devcontainer/scripts/on-create.sh) andcopilot-setup-steps.ymlto install and verify a SHA-pinnedosv-scannerfor local and CI-based vulnerability scanning, ensuring reproducible and secure builds.Documentation and Compliance
docs/security/vex-verification.md(consumer guide) anddocs/agents/security/vex-generator.md(agent docs); added control SC-9 todocs/security/security-model.md; linked the guide fromdocs/security/README.md; and updatedSECURITY.mdwith the.openvex.jsonartifact row, a VEX verification subsection, and a signed-artifacts row.Vocabulary and Codebase Hygiene
PYSEC,deprioritize, and other VEX/CVE terms) to improve codebase consistency and reduce false-positive linter warnings.These changes collectively deliver a robust, auditable, and automatable VEX workflow, raising the security assurance and transparency of HVE Core.
Artifact inventory
security/vex/hve-core.openvex.json(OpenVEX v0.2.0 document);attest-and-upload-vexjob inrelease-stable.yml(provenance + VEX-as-predicate-over-SBOM attestations).github/skills/security/openvex-spec/(SKILL + schema, status-logic, and CVE-data-source references);vex-standardsandvex-generationinstructions.github/agents/security/vex-generator.agent.md+subagents/cve-analyzer.agent.md/vex-scanand/vex-triage; collection registration;.github/PULL_REQUEST_TEMPLATE/vex-triage.md.github/workflows/vex-detect.yml(OSV-Scanner scan, diff against the VEX doc, file a triage issue).github/workflows/vex-draft.md+ compiledvex-draft.lock.yml(gh-aw, engine: copilot)osv-scannerinstall in.devcontainer/scripts/on-create.shandcopilot-setup-steps.ymldocs/security/vex-verification.md,docs/agents/security/vex-generator.md; updates todocs/security/security-model.md(control SC-9),docs/security/README.md, andSECURITY.mdArchitecture
flowchart TB subgraph Tooling["Tooling track (the brain)"] Skill["openvex-spec skill"] Agent["vex-generator agent + cve-analyzer subagent"] Prompts["/vex-scan + /vex-triage"] Skill --> Agent --> Prompts end subgraph Workflow["Workflow track (the plumbing)"] Foundation["VEX document + release attestation"] Detect["vex-detect.yml"] Draft["vex-draft.md (gh-aw)"] Foundation --> Detect --> Draft end Agent -. powers .-> Draft Workflow --> Docs["Documentation"] Tooling --> DocsHow it works once live
vex-detect.yml) re-scans on a schedule and after each release, diffs OSV-Scanner findings against the VEX document, and files a single deduplicated triage issue for untriaged or non-terminal-status CVEs.vex-draft.md) triggers off the detection run, invokes the VEX Generator agent to enrich each CVE, analyze reachability, route by confidence, and opens one pull request with an updated OpenVEX document.trivy --vex/grype --vexto suppressnot_affectedfindings.Related Issue(s)
#1220
#1221
Type of Change
Select all that apply:
Code & Documentation:
Infrastructure & Configuration:
AI Artifacts:
prompt-builderagent and addressed all feedback.github/instructions/*.instructions.md).github/prompts/*.prompt.md).github/agents/*.agent.md).github/skills/*/SKILL.md)Other:
.ps1,.sh,.py)Sample Prompts (for AI Artifact Contributions)
User Request:
This invokes the VEX Generator agent through the
/vex-scanprompt (Mode 1)./vex-triage report=osv-results.jsonruns Mode 2 against an existing scan report instead.Execution Flow:
GHSA-/PYSEC-aliases) and enriches from OSV.dev, NVD, and the GitHub Advisory Database, querying each source by the id it is keyed on and falling back across aliases.CVE Analyzersubagent, which traces the import path, confirms dead code, or identifies a mitigation, with file and line citations.under_investigationand nevernot_affected.Output Artifacts:
The updated
security/vex/hve-core.openvex.json, for example:{ "@context": "https://openvex.dev/ns/v0.2.0", "@id": "https://github.com/microsoft/hve-core/security/vex/2026-06-18", "author": "Microsoft HVE Core Maintainers", "version": 2, "statements": [ { "vulnerability": { "name": "CVE-2026-53550", "aliases": ["GHSA-h67p-54hq-rp68"] }, "products": [{ "@id": "pkg:npm/js-yaml@3.14.2" }], "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path" } ] }Success Indicators:
The document validates against the OpenVEX v0.2.0 schema; every
not_affectedstatement carries a justification code and code-citation evidence; ambiguous findings areunder_investigation; and the triage report lists the human-touch items. The PR touches only the VEX document.For detailed contribution requirements, see:
Testing
The capability was validated across seven layers: static re-validation, OpenVEX schema conformance, a local run of the detection workflow against the real dependency set, a bounded run of the agent pipeline, the integration seams, the release-attestation wiring (static), and a live end-to-end run of the drafting workflow.
Live drafting run (gh-aw, GitHub Copilot engine)
A real run of the
VEX Draftingworkflow on the fork, dispatched against a seeded detection issue, drafted a schema-valid OpenVEX update as a pull request:The run confirmed the full pipeline end to end: the activation guard fired correctly (no spurious noop), the agent ran under the Copilot engine, CVE enrichment resolved advisories across OSV.dev, NVD, and the GitHub Advisory Database, and the safe-output PR touched only
security/vex/hve-core.openvex.json. The agent produced evidence-backednot_affecteddeterminations (each with a justification code and CVSS / codebase citations), and the forbidden-transition guard held (no unevidencednot_affected).Validation results
The following all pass on this branch:
gh aw compile(0 errors / 0 warnings),lint:yaml(actionlint),lint:md,lint:frontmatter,lint:md-links,spell-check,lint:dependency-pinning,lint:permissions,validate:skills, andlint:ai-artifacts.Checklist
Required Checks
AI Artifact Contributions
/prompt-analyzeto review contributionprompt-builderreviewRequired Automated Checks
The following validation commands must pass before merging:
npm run lint:mdnpm run spell-checknpm run lint:frontmatternpm run validate:skillsnpm run lint:md-linksnpm run lint:psnpm run plugin:generatenpm run docs:testSecurity Considerations
CVE advisory data is used under per-source licenses: NVD (US Government public domain) for CVSS and CWE; OSV.dev (mixed, routed by record prefix); GitHub Advisory Database (CC-BY-4.0) for identifiers, factual metadata, and reference URLs only. The agent writes original impact and remediation prose and does not quote or closely paraphrase advisory text. OpenVEX template text is CC0. Workflows declare least-privilege permissions, pin actions to SHA, and verify the
osv-scannerdownload by checksum.Additional Notes
Maturity and known follow-ups:
experimentalmaturity. Promotion tostablefollows validation across three or more codebases with a 5% or lower false-positive rate onnot_affecteddeterminations.GH_AW_GITHUB_TOKENseam (falling back toGITHUB_TOKEN); populate it from a GitHub App so drafted PRs trigger downstream checks.