# description
Per-vulnerability-disclosure attestation envelope binding {vulnerability-id, affected-artifact-sha, severity, reporter-DID, disclosure-timeline} to a cryptographic chain. Closes SYNTHESIS-acquisition Round 17 P1 [[ai-security-disclosure]] V1 ship-first action — the cited-evidence substrate that cycle-316 ip.review.attestation.v1 already references in citedEvidenceShaArray.kind enum. TWELFTH JSON Schema in IntelligencePro's catalog. Anchors the Aug-2025 Kudelski Security disclosure pattern (CodeRabbit RCE exposing write access to ~1M repos) — when an AI code reviewer's OWN runtime is the vulnerability, the same agent cannot self-disclose; a detached peer attestation is the only architecture that can. Designed for: HackerOne (programs + reports) + Bugcrowd + Intigriti + YesWeHack + GitHub Security Advisories (GHSA-xxxx-xxxx-xxxx) + MITRE CVE Numbering Authorities (CVE-YYYY-NNNNN) + NVD + OSV.dev (Open Source Vulnerabilities aggregator) + OSV-Scanner + Snyk vulnerability database + Tenable + Qualys + CISA KEV (Known Exploited Vulnerabilities catalog) + NIST CVSS v4.0 + EPSS (Exploit Prediction Scoring System). Composes UPSTREAM with ip.sandbox.run.attestation.v1 (cycle 307) via reproducerSandboxRunId — the disclosure can cite the exact sandboxed PoC that triggered the vulnerability. Composes DOWNSTREAM with ip.review.attestation.v1 (cycle 316) via citedEvidenceShaArray[] — a ip-merge-gate reviewer cites this disclosure to block a PR that introduces a known-vulnerable dependency. Composes with ip.governance.compliance.v1 (cycle 315) via evidenceShaArray[] — a SOC 2 / ISO 27001 / NIST 800-53 control can cite a disclosure record as evidence of vulnerability-management practice.

# $comment
Discovery: https://ip.tekton.cc/.well-known/ip-knowledge.json (full descriptor) | Badge: https://ip.tekton.cc/api/badge/v1/attestation/vulnerability.disclosure.v1/<subjectSha256> (shields.io endpoint) | Free dry-run: POST https://ip.tekton.cc/api/credentials/dry-run with body {kind:"vulnerability.disclosure.v1", body:<candidate>} (no auth required, validates against this schema) | Verification recipe: https://ip.tekton.cc/docs/verification-recipe.md (3-layer trust model + curl trail) | Revocation: https://ip.tekton.cc/credentials/status/v1 (W3C BitstringStatusList v1.0; check bit at credentialStatus.statusListIndex) | DUPLICATE-KEY HISTORY (ir-801-P1-2 cycle 813 note): cycle 783 (commits ad1f706 + 05e758f, 2026-05-18 morning) shipped this schema with TWO duplicate `chain` top-level properties from two convergent commits (one with parentKind=[ip.governance.compliance.v1], one with parentKind=[ip.sandbox.run.attestation.v1, ip.review.attestation.v1]). Cycle 796 (commit 58a554b, 2026-05-18 ~15:28 UTC) merged into ONE chain block with the full enum [sandbox-run, review, governance]. The ~13-cycle window served a duplicate-key JSON document; RFC 8259 §4 leaves duplicate-key behavior unspecified (Ajv/serde/encoding-json/Python-json/jq all keep the LAST value; some streaming parsers keep the FIRST). CONSUMERS WHO CACHED THE CYCLE-783-ERA SCHEMA SHA INTO A BUILD ARTIFACT (Cloudflare-Worker bundled-fetch asset cache, Dockerfile-baked schema bundle, Inspect AI frozen schema fixture) MUST refetch — the cycle-796 merged shape has a different sha256 than the cycle-783 duplicate-keyed shape, and any consumer that pinned the older sha holds a not-cycle-796-compatible parent-kind enum. Refetch URL: https://ip.tekton.cc/credentials/vulnerability-disclosure/v1 (returns the cycle-796 merged shape; the cycle-783 sha is no longer served).

# x-controlMappingRefs.$comment
Cycle 720 (SP-716-P1-4 close): bidirectional back-link to the framework mapping docs. Inline CISA/MITRE references in property descriptions are preserved (they bind specific identifier formats); this block names the control objectives this schema EVIDENCES. A CISA SSDF or NIST 800-53 importer reads these refs to bind disclosure records to vulnerability-management practices.

# x-controlMappingRefs.iso42001Aims[].note
RC-737-P1-2 (cycle 752): cite-correction. Pre-cycle-752 this referenced A.6.1.6 which is NOT a published ISO/IEC 42001:2023 Annex A control — A.6.1 covers AI system life cycle management (A.6.1.2 Objectives + A.6.1.3 Processes only). The semantically correct incident-reporting control in published 42001 is A.6.2.8 'Reporting of AI system incidents.' Disclosure records ARE the incident-response evidence pack the published standard requires.

# x-controlMappingRefs.iso42001Aims[].note
Monitoring activities — affectedArtifactSha256 binds the disclosure to a sha-pinned artifact for impact analysis

# x-controlMappingRefs.nistAiRmf[].note
Risk-response prioritization — severity + EPSS + KEV signals feed the response-priority decision

# x-controlMappingRefs.nistAiRmf[].note
GenAI Profile — security — the disclosure attestation is the security-incident artifact

# x-controlMappingRefs.euAiAct[].note
Reporting of serious incidents — disclosure attestation IS the structured report (timeline + severity + reporter identity)

# x-controlMappingRefs.euAiAct[].note
Accuracy, robustness, cybersecurity — disclosure records are the cybersecurity evidence trail

# x-controlMappingRefs.nistSsdf[].note
Acquire and maintain well-secured software — disclosure attestations are the maintain-step evidence

# x-controlMappingRefs.nistSsdf[].note
Respond to vulnerabilities — the disclosure timeline (discoveredAt → disclosedAt) is the response-cadence artifact

# x-controlMappingRefs.iso42001RiskRegister[].note
Signed disclosure records replace ad-hoc email/Slack vulnerability reports — provides auditable timeline

# properties.schemaVersion.description
Semver of this schema. Bumps to 2.0.0 land at /credentials/vulnerability-disclosure/v2 — v1 stays immutable (see /docs/schema-versioning.md for the cycle-726 canonical bump-mechanics + soft-change-detection contract).

# properties.disclosureId.description
Unique RFC 4122 UUID v4 or v7 — the CP-side canonical identifier for this disclosure attestation row. Distinct from vulnerabilityId (which is the external CVE/GHSA/etc.) because the SAME vulnerability may have multiple ip.vulnerability.disclosure rows over time (initial → CVSS-rescore → vendor-patch-confirmed → KEV-listed). Links to ip.attestation.event.v1 wire row via ipAttestationEventId.

# properties.vulnerabilityId.description
External canonical identifier. Accepts MITRE CVE (CVE-YYYY-NNNNN; 4-7 digit serial), GitHub Security Advisories (GHSA-xxxx-xxxx-xxxx; 12 chars in 4-4-4 groups), OSV.dev native IDs (OSV-PREFIX-NNNN), Snyk database IDs (SNYK-ECOSYSTEM-PACKAGE-NNNN), and CP-namespaced pre-publication IDs (ip-vuln-<hash>) for embargoed disclosures awaiting CVE-NA assignment. Downstream verifiers cross-reference: NVD for CVE, GitHub Advisory DB for GHSA, OSV.dev for OSV, Snyk for SNYK. Multiple IDs for the same vuln across databases → emit MULTIPLE ip.vulnerability.disclosure rows linked via a shared affectedArtifactSha256.

# properties.affectedArtifactSha256.description
Sha256 of the canonical bytes of the vulnerable artifact. For PyPI/npm packages: sha256 of the published wheel / tarball at the affected version. For container images: sha256 of the image manifest digest. For binaries: sha256 of the bytes. For git-tracked source: sha256 of the git tree at the vulnerable commit. THIS is the load-bearing field — disclosure verifiers MUST be able to recompute this hash against the affected artifact in their supply chain and prove they're actually running the vulnerable build, not just citing a CVE ID that happens to share a name. Defeats the 'CVE-listed-but-affected-version-mismatch' class of noise that drowns dependency-bot output.

# properties.ecosystem.description
Package / artifact ecosystem the affected artifact lives in. Aligned with OSV.dev ecosystem identifiers + Snyk ecosystem identifiers. 'huggingface-model' and 'huggingface-dataset' are CP additions for the AI-supply-chain vulnerability class (model-poisoning, dataset-poisoning). 'github-actions' is a CP addition for the Action-supply-chain class (the same pattern that produced the CodeRabbit RCE). Optional but strongly recommended — verifiers use this to pick the right ecosystem-specific resolver (e.g. pip-audit vs npm audit vs OSV-Scanner).

# properties.affectedRange.description
Ecosystem-conventional version range the disclosure applies to. Format is ecosystem-defined: PEP 440 for pypi ('>=1.2.0,<1.4.3'), semver-range for npm ('>=2.0.0 <2.5.1'), GHSA-style for github-actions ('< 4.2.1'). Optional — affectedArtifactSha256 is the cryptographic anchor; affectedRange is for human + dependency-bot consumption. When present, MUST be compatible with the artifact identified by affectedArtifactSha256.

# properties.severity.description
Severity assessment. CVSS-vector is the load-bearing field for machine verification; qualitative is for human display. CP requires at least ONE of {cvssV4Vector, cvssV3Vector, qualitative} to be present — enforced semantically at the producer because JSON Schema 2020-12 anyOf in conditionally-required is not universally supported. Producers SHOULD emit cvssV4Vector for new disclosures (CVSS v4.0 went GA Nov-2023; NVD began publishing v4 vectors 2024-Q4).

# properties.severity.properties.cvssV4Vector.description
CVSS v4.0 vector string (per FIRST.org specification). Format: 'CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N'. The base-score derives from this vector; downstream verifiers MAY recompute and reject if the emitted baseScore disagrees by more than 0.1.

# properties.severity.properties.cvssV3Vector.description
CVSS v3.1 (preferred) or v3.0 vector string. Format: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H'. Maintained for compatibility with NVD's legacy CVSS pipeline (NVD continues to emit v3.1 alongside v4 through 2027). When BOTH cvssV4Vector and cvssV3Vector are present, downstream consumers prefer v4.

# properties.severity.properties.baseScore.description
Pre-computed base score [0.0-10.0]. Derives from cvssV4Vector or cvssV3Vector — emitted for fast triage so consumers don't have to evaluate the vector. If a consumer recomputes, the recomputed value MUST be within 0.1 of this field.

# properties.severity.properties.qualitative.description
Qualitative severity bucket per FIRST.org CVSS qualitative mapping (none=0.0, low=0.1-3.9, medium=4.0-6.9, high=7.0-8.9, critical=9.0-10.0). For human display + dashboard filters.

# properties.severity.properties.epssScore.description
EPSS (Exploit Prediction Scoring System) probability [0.0-1.0] from first.org/epss. Daily-updated probability that the vulnerability will be exploited in the wild within the next 30 days. Higher = more urgent triage. Empty for CVEs not yet in EPSS coverage.

# properties.severity.properties.cisaKev.description
True if the vulnerability appears in CISA's KEV (Known Exploited Vulnerabilities) catalog at the time of disclosure emission. KEV = confirmed in-the-wild exploitation; federal civilian agencies have a fixed remediation deadline. Downstream ip-merge-gate reviewers can mark a PR introducing a KEV-listed dependency as auto-block.

# properties.discoveredAt.description
Epoch milliseconds when the vulnerability was first discovered (by the reporter, not when it was publicly disclosed). Required: the gap (disclosedAt - discoveredAt) is the responsible-disclosure-window evidence — a regulator can verify whether a vendor met the 90-day / 120-day window the reporter granted.

# properties.disclosedAt.description
Epoch milliseconds when the disclosure went public. For CVE-tracked vulnerabilities: NVD publication timestamp. For GHSA: advisory publication timestamp. For HackerOne / Bugcrowd public disclosure: program-side disclosure timestamp. MUST be >= discoveredAt.

# properties.patchedAt.description
Optional: epoch milliseconds when a fixed-version artifact was published. fixedArtifactSha256 SHOULD also be set when patchedAt is set. Absent → the vulnerability is unpatched at the time of attestation emission.

# properties.fixedArtifactSha256.description
Optional: sha256 of the canonical bytes of the FIXED artifact (e.g. the patched npm package version's tarball). Lets a downstream dependency-resolver prove it actually picked up the fix, not just bumped the version string. Producers SHOULD emit this when patchedAt is set.

# properties.reporterDid.description
DID of the reporter (individual researcher, security team, automated scanner). did:web for institutional reporters (Kudelski Security, Trail of Bits, Trustwave, GitHub Security Lab, Google Project Zero); did:key for individual researcher submissions. The DID resolves to a JWKS that verifies the `signature` field below. Pinning reporter identity defeats the unsigned-bot-spam class of dependency-bot noise.

# properties.vendorDid.description
Optional: DID of the affected vendor (the maintainer of the vulnerable artifact). Lets a downstream verifier cross-check whether the disclosure was vendor-acknowledged or unilateral. did:web typically resolves to the vendor's published security.txt + JWKS.

# properties.reproducerSandboxRunId.description
Optional: UUID of a ip.sandbox.run.attestation.v1 row that successfully reproduced the vulnerability in a deterministic sandbox. UPSTREAM chain to cycle 307 schema. A ip.review.attestation.v1 ip-merge-gate verifier can walk: review.citedEvidenceShaArray → vulnerability.disclosure → reproducerSandboxRunId → ip.sandbox.run.attestation → exact PoC environment. Without this, a vulnerability claim is unfalsifiable.

# properties.cweIds.description
Optional: array of MITRE CWE (Common Weakness Enumeration) IDs that classify the vulnerability's root cause. Format: 'CWE-NNN' (e.g. CWE-77 for command-injection, CWE-79 for XSS, CWE-22 for path-traversal). Maps to CWE Top 25 + OWASP Top 10 for compliance reporting. Multiple CWEs allowed because most real vulnerabilities have stacked weaknesses.

# properties.exploitabilityNotes.description
Optional: free-form notes on real-world exploitability — preconditions, attack chain, observed-in-the-wild evidence, EPSS interpretation. NOT meant to replace a full vulnerability report; this is the field a ip-merge-gate reviewer reads when deciding whether to block a PR. 8KB cap enforces operational-summary, not full-PoC.

# properties.ipAttestationEventId.description
Optional: UUID of the ip.attestation.event.v1 wire row that envelopes this disclosure for transport. Lets a downstream consumer walk the wire-shape substrate back to the canonical event chain. Same pattern as the other 11 cp.* attestation schemas.

# properties.signature.description
Ed25519 signature (128 hex chars = 64 raw bytes) over the JCS-canonical bytes (RFC 8785) of this attestation body MINUS the `signature` and `publicKey` fields. Verify against the publicKey below — or for richer trust, resolve reporterDid to its JWKS and confirm the publicKey field matches the verificationMethod-keyed entry. SP-607-P0-2 partial close (cycle 609): pre-cycle-609 this field was shaped as an opaque object (W3C VC 2.0 DataIntegrityProof), making vulnerability-disclosure the sole catalog outlier — 18 of 19 sibling attestation schemas use this string-hex Ed25519 pair, so a verifier walking the catalog now sees ONE uniform crypto envelope across all 19 attestation kinds. The outer W3C VC 2.0 DataIntegrityProof envelope is still produced by the platform at issuance via app/lib/canonical-json.ts + eddsa-jcs-2022 cryptosuite — but it wraps THIS string-hex signature in the transport-layer VC, rather than replacing it in the attestation body. Same dual-form pattern the other 18 schemas already document. ⚠ INTEGRITY GAP (aa-824-P0-1, cycle 848 honest disclosure): `chain.*` and `extra` are presently OUTSIDE this signature pre-image. A wire-path or post-hoc rewrite of `chain.parentSha256` / `chain.parentKind` / `chain.parentAttestationId` does NOT invalidate this `signature`. Offline verifiers using `signature`+`publicKey` (the documented embedded-verification path) MUST treat `chain.*` as ADVISORY pointer-shape, NOT cryptographically bound to this attestation. For full-integrity verification including chain pointers, fetch the W3C DataIntegrityProof envelope from /credentials/<sha>/v1 and verify against the proof.cryptosuite=eddsa-jcs-2022 signature (which signs the FULL canonical-JSON body including chain). Cycle-484 added the chain block; cycles 778-784 swept it; the signature pre-image was not re-derived. Migration target: v2 schema slug ($id pin per cycle-462). See cycles 825-829 (5/5 wedge-tier ring) + cycle 830 (verification-recipe.md dual-path teaching) for the canonical write-up; cycle 848 fans this disclosure to the 12 remaining chain-bearing leaf schemas in one batch.

# properties.publicKey.description
Ed25519 public key (32 raw bytes = 64 hex) corresponding to the signature above. Verifier MAY prefer to resolve via reporterDid's JWKS — this field exists for offline / embedded verification when network resolution is unavailable. Mirrors legal-citation's publicKey shape (SP-607-P0-2 catalog-parity fix, cycle 609).

# properties.chain.properties.parentSha256.description
Sha256 of the canonical-JSON bytes of the parent attestation. For a vulnerability.disclosure the parent is one of THREE legitimate upstream paths: (1) ip.sandbox.run.attestation.v1 — the cryptographically-attested reproducer PoC (dominant for HackerOne / Bugcrowd / GHSA / NVD / OSV / CVE workflows where the reproducer sandbox IS the load-bearing evidence); (2) ip.review.attestation.v1 — when the disclosure originated from a peer-attested code review (the cycle-769 ip-merge-gate composition pattern where a reviewer flagged a vulnerable dependency); (3) ip.governance.compliance.v1 — the organizational policy row that governs CVE/GHSA/KEV ingestion, CVSS scoring, KEV-listing review (anti-rogue-CVE / anti-typosquatted-GHSA substrate; a disclosure without a governance parent is unsigned-by-program). ⚠ Cycle 493 honest-disclosure: platform does NOT verify parent-existence at issuance; consumers walk the chain against their own registry per /docs/verification-recipe.md.

# properties.chain.properties.parentKind.description
Kind identifier of the parent attestation. vulnerability.disclosure has three legitimate upstream paths: sandbox-run (reproducer PoC), review-attestation (peer-attested code review), governance-compliance (disclosure-program policy row).

# properties.chain.properties.parentAttestationId.description
Optional UUID of the parent attestation — convenience for consumers that index by id rather than by sha256.

# properties.chain.description
Cycle 796 (rc-795-P0-3 close, merging the duplicate-chain regression from cycle 783's two convergent commits): uniform upward chain link per the cycle-484 substrate. Pre-cycle-783 ip.vulnerability.disclosure.v1 had no chain block at all. Cycle 783 added TWO sibling `chain` blocks (the parallel agent's batch C added a governance-compliance parent variant; my cycle 783 added a sandbox-run / review-attestation parent variant). RFC 8259 §4 leaves duplicate-key behavior unspecified — different consumers saw different schemas from the same canonical bytes (rc-795 regulatory-compliance audit P0-3). Cycle 796 merges the two into ONE chain block with the parentKind enum widened to all three legitimate upstreams. Block is OPTIONAL (not in required[]) so back-compat preserved. Anchors the Aug-2025 Kudelski Security CodeRabbit RCE disclosure pattern (~1M repos) — when the AI code reviewer's OWN runtime is the vulnerability, the disclosure must chain to a SANDBOXED PoC, a PEER-REVIEWED finding, or the GOVERNANCE row authorizing the program, not to the agent's own self-disclosure.