Safeguard
Application Security•

Publishing a Security Advisory: OSV, CSAF and a Customer Notice Template

A fix is not finished until customers and their tools can read about it. One advisory page, a machine readable OSV or CSAF record, and a customer notice you can adapt.

Safeguard Security Team
6 min read

On 13 October 2026 the OSV schema, the format behind most open source vulnerability feeds, stood at version 1.9.2 on its public specification page. Only two fields are required: id and modified, plus schema_version for any version above 1.0.0. Everything else, including the affected packages, is optional, though an entry without it is not much use.

That low bar is good news for a small vendor. You can publish a record a scanner understands in an afternoon. This post covers what to publish, in which format, and what to tell customers.

What's affected

Any company that ships a fix for a vulnerability in something customers run, whether a library, an agent, a container image or an on-premises product. Three audiences read your advisory, and each wants something different:

ReaderWantsFormat
Engineer on callAffected versions, fixed version, workaroundA short web page
Scanner or SBOM toolPackage name, version ranges, IDOSV JSON, or a CVE record
Customer security teamProduct status per version, remediation, dateCSAF, or a PDF plus the web page

GitHub's advisory database publishes its advisories "as JSON files in the Open Source Vulnerability (OSV) format", so if your code is on GitHub, a published repository advisory already gives you OSV output.

How to check if you're exposed

Ask whether a customer could learn about your last fix without emailing you. Open your advisories page and your feed in a private window.

curl -s -o /dev/null -w '%{http_code}\n' https://example.com/security/advisories
curl -sI https://example.com/security/feed.xml | head -n 3

If the page is missing, or the only announcement was a changelog line, that is the gap.

What to do now

  1. Publish a web advisory first. Include the identifier, the affected and fixed versions, the severity and the weakness type, a workaround if one exists, and credit for the reporter.
  2. If you are not on GitHub, add an OSV record for each advisory. A minimal example:
{
  "schema_version": "1.9.2",
  "id": "x_ACME-2026-001",
  "modified": "2026-10-18T09:00:00Z",
  "published": "2026-10-18T09:00:00Z",
  "summary": "Stored XSS in the report viewer",
  "affected": [{
    "package": { "ecosystem": "npm", "name": "acme-sdk" },
    "ranges": [{ "type": "SEMVER",
                 "events": [{ "introduced": "0" }, { "fixed": "2.4.1" }] }]
  }],
  "references": [{ "type": "ADVISORY",
                   "url": "https://example.com/security/advisories/2026-001" }]
}

The spec says local, non-aggregated databases use the x_ prefix for IDs. Once you have a CVE, use it as an alias instead.

  1. For customers who ask for CSAF, know what it requires. CSAF 2.0 became an OASIS Standard on 18 November 2022, and ISO/IEC 20153:2025 adopts it. The only mandatory top level property is document. Under it, five properties are mandatory: category, csaf_version, publisher, title and tracking. Under tracking, six are mandatory: current_release_date, id, initial_release_date, revision_history, status and version.
{
  "document": {
    "category": "csaf_security_advisory",
    "csaf_version": "2.0",
    "publisher": { "category": "vendor", "name": "Example Co",
                   "namespace": "https://example.com" },
    "title": "Stored XSS in Example SDK report viewer",
    "tracking": {
      "id": "EXAMPLE-2026-001",
      "status": "final",
      "version": "1",
      "initial_release_date": "2026-10-18T09:00:00Z",
      "current_release_date": "2026-10-18T09:00:00Z",
      "revision_history": [{ "date": "2026-10-18T09:00:00Z",
                             "number": "1", "summary": "Initial release" }]
    }
  }
}

That is only the skeleton. A useful security advisory also lists the product tree and vulnerabilities, so generate it from a tool instead of hand editing.

  1. Notify downstream parties ahead of release if you have a list. Django, for example, notifies a list of operating system vendors and distributors about a week before disclosure, then posts a blog entry and notifies its announce lists on the day.
  2. Send customers a short notice:
Subject: Security update for Example SDK (fixed in 2.4.1)

What happened: A stored cross-site scripting flaw in the report viewer
affects versions before 2.4.1.
Who is affected: Anyone running Example SDK versions below 2.4.1 with
the report viewer enabled.
What to do: Upgrade to 2.4.1. If you cannot today, disable the report
viewer. Details: https://example.com/security/advisories/2026-001
Evidence of abuse: We have no indication of exploitation as of 18 Oct.
Questions: security@example.com
  1. Update the advisory when facts change, and keep the revision history. If you run a status page, post a short note there and link to the advisory.

If the issue affected your running service and not only a shipped product, follow the advisory with a short postmortem within a few days: a timeline in UTC, what was exposed, what you changed, and the date by which each change will be done. Keep it factual, link it from the advisory and from your status page, and close it by updating the page when the last action ships. A postmortem that lists actions without dates reads as a promise nobody tracks.

How to avoid this trap

  1. Do not publish the advisory before the fix is downloadable. Rule of thumb: advisory and release go out together.
  2. Do not hand edit CSAF. One typo can make the file invalid, and customers' tooling will reject it.
  3. Do not say "no evidence of exploitation" unless you looked. Say what you checked and when.
  4. Do not change an advisory silently. Add a revision line with the date.

Why it matters

A tool that reads your OSV or CVE record can tell a customer in seconds whether they run an affected version. A human reading a PDF takes days. For a small vendor, that is the difference between a quiet patch cycle and a week of support tickets.

A short, plain customer notice also helps after the fact. When a security reviewer asks how you handle disclosure, you can show a dated advisory, a feed and a notice that followed your own template.

Try it yourself

Write the OSV record for one fix in your changelog, then see how a VEX and CSAF view expresses "affected," "not affected" and "fixed" for the same issue.

Click through it at your own pace, or open it full screen.

Quick check

Which fields does an OSV record strictly require?

id and modified, plus schema_version for versions above 1.0.0. All other fields are optional.

Is the top level vulnerabilities property mandatory in CSAF 2.0?

No. The only mandatory top level property is document. product_tree and vulnerabilities are optional, though a useful advisory includes them.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.