Skip to content

Osv Schema

ossf.github.io August 15, 2026

This document defines a standard interchange format for describing vulnerabilities in open source packages.

We hope to define a simple format that all vulnerability databases can export, to make it easier for users, security researchers, and any other efforts to consume all available databases. Use of this format would also make it easier for the databases themselves to or cross-check information. Ultimately, this format aims to enable automated, accurate, and distributed management of vulnerabilities in open source dependencies.

This format is stable, but further backwards compatible changes may still be made. Feedback from maintainers of other vulnerability databases and security response teams is most welcome. Please feel free to create an issue in this repo .

The current list of databases exporting this format can be found here .

The format is a JSON-based encoding format, using the following informal schema. The exact details of each field are elaborated in the section. All strings contain UTF-8 text.

A JSON Schema for validation is also available here .

Again, this document is only the JSON encoding the database serves to consumers, which could be applications or other databases. A database might store its entries in an entirely different format, or it might store them using this schema but in a more human-editable encoding, such as TOML or YAML. For serving, only the JSON encoding format is allowed, not a transliteration into any other encoding.

Overall, the approach of this schema is to define only the fields that absolutely must be shared between databases, leaving customizations to the “ecosystem_specific” and “database_specific” blocks (see below)

The schema_version field is used to indicate which version of the OSV schema a particular vulnerability was exported with. This can help consumer applications decide how to import the data for their own systems and offer some protection against future breaking changes. The value should be a string matching the OSV Schema version, which follows the SemVer 2.0.0 format, with no leading “v” prefix. If no value is specified, it should be assumed to be 1.0.0 , matching version 1.0 of the OSV Schema. Clients can assume that new minor and patch versions of the schema only add new fields, without changing the meaning of old fields, so that a client that knows how to read version 1.2.0 can process data identifying as schema version 1.3.0 by ignoring any unexpected fields.

The id field is a unique identifier for the vulnerability entry. It is a string of the format - , where DB names the database and ENTRYID is in the format used by the database. For example: “OSV-2020-111”, “CVE-2021-3114”, or “GHSA-vp9c-fpxx-744v”.

The x_ prefix can be used to denote a local database that isn’t aggregated by OSV.dev, allowing external records to be schema-compliant. For example: “x_CUSTOM-0001”.

The defined database prefixes and their “ ” databases are:

Publishers should publish information within their reasonable scope or ecosystem. If one wants to derive their ID from a CVE record, adding the database prefix is sufficient to communicate this. e.g. DEBIAN-CVE-2000-0001 .

The modified field gives the time the entry was last modified, as an RFC3339-formatted timestamp in UTC (ending in “Z”). Given two different entries claiming to describe the same id field, the one with the later modification time is considered authoritative.

The id and modified fields are required. For schema versions above 1.0.0, the schema_version field is also required. All other fields are optional, although of course an entry with no other metadata is not particularly useful. (It could potentially stand for a reserved ID with no other public information.)

The published field gives the time the entry should be considered to have been published, as an RFC3339-formatted time stamp in UTC (ending in “Z”).

The withdrawn field gives the time the entry should be considered to have been withdrawn, as an RFC3339-formatted timestamp in UTC (ending in “Z”). If the field is missing, then the entry has not been withdrawn. Any rationale for why the vulnerability has been withdrawn should go into the summary text.

The aliases field gives a list of IDs of the same vulnerability in other databases, in the form of the id field. This allows one database to claim that its own entry describes the same vulnerability as one or more entries in other databases.

Two vulnerabilities can be described as aliases if they affect any given software component the same way: either both vulnerabilities affect the software component or neither do. A subsequent patch addresses both of the vulnerabilities (and no others), and vice versa.

Aliases should be considered symmetric (if A is an alias of B, then B is an alias of A) and transitive (If A aliases B and B aliases C, then A aliases C).

Aliases should not be used to refer to vulnerabilities in packages upstream or downstream in a software supply chain from the given OSV record’s affected package(s). For example, if a CVE describes a vulnerability in a language library, and a Linux distribution package contains that library and therefore publishes an advisory, the distribution’s OSV record must not list the CVE ID as an alias. Similarly, distributions often bundle multiple upstream vulnerabilities into a single record. To refer to these upstream vulnerabilities, upstream should be used.

The upstream field gives a list of IDs of upstream vulnerabilities that are referred to by the vulnerability entry.

For example, a downstream package ecosystem (such as a Linux distribution) may issue its own advisories that include (possibly multiple) upstream vulnerabilities.

upstream should be considered transitive but not symmetric. For example, if B is an upstream vulnerability for A, and C is an upstream vulnerability for B, then C is also an upstream vulnerability for A. At the same time, if B is an upstream vulnerability for A, then A cannot be an upstream vulnerability for B.

The related field gives a list of IDs of closely related vulnerabilities, such as:

Related vulnerabilities are symmetric but not transitive.

The summary field gives a one-line, English textual summary of the vulnerability. It is recommended that this field be kept short, on the order of no more than 120 characters.

The details field gives additional English textual details the vulnerability.

The summary field is plain text.

The details field is CommonMark markdown (a subset of GitHub-Flavored Markdown). Display code may at its discretion sanitize the input further, such as stripping raw HTML and links that do not start with http:// or Databases are encouraged not to include those in the first place. (The goal is to balance flexibility of presentation with not exposing vulnerability database display sites to unnecessary vulnerabilities.)

The severity field is a JSON array that allows generating systems to describe the severity of a vulnerability using one or more quantitative scoring methods. Each severity item is a JSON object specifying a type and score property, as well as an optional source property, described below.

The severity[].type property must be one of the types defined below, which describes the quantitative method used to calculate the associated score .

The severity[].score property is a string representing the severity score based on the selected severity[].type , as described above.

The severity[].source property is an optional string indicating the origin of the severity assessment.

If source is omitted, the rating is implicitly attributed to the database (as identified by the record’s id field), whether as author or endorser.

The affected field is a JSON array containing objects that describes the affected package versions, meaning those that contain the vulnerability.

Within each object in the affected array, the package field identifies the package containing the vulnerability. In most cases, there should be exactly one entry in the affected array per affected package to describe all affected versions. In rare cases, for example if the ecosystem_specific encodes platform information that doesn’t apply equally to all listed versions and ranges, a separate entry with the same package in the affected array may be needed.

The versions field can enumerate a specific set of affected versions, and the ranges field can list ranges of affected versions, under a given defined ordering. A version is considered affected if it lies within any one of the ranges or is listed in the versions list. Pseudocode for evaluating if a given version is affected is available here .

The versions list is generally recommended to always be present, to allow software to easily answer the question “is this specific version affected?” without having to contain code specific to every different ecosystem. If the affected versions can be accurately summarized by one or more non-overlapping ranges, they may be encoded using the ranges field with an appropriate type (see below). In this case, the ranges act as a kind of compact form of a larger versions list. Tooling and infrastructure such as are able to expand these ranges for supported ecosystems into the versions list for easier consumption. Products or ecosystems that do not use version identifiers that can be represented as ranges must include the enumerated versions list instead.

The affected object’s package field is a JSON object identifying the affected code library or command provided by the package. The object itself has two required fields, ecosystem and name , and an optional purl field.

The ecosystem identifies the overall library ecosystem. It must be one of the strings in the table below. The name field is a string identifying the library within its ecosystem. The two fields must both be present, because the ecosystem serves to define the interpretation of the name .

Use the wildcard package name * to indicate that an advisory affects all packages within the specified ecosystem . For example, this is useful when an ecosystem version reaches end-of-life (EOL) and receives no further security support.

The purl field is a string following the Package URL specification that identifies the package, without the @version component. This field is optional but recommended.

Different ecosystems can define the same names; they identify different packages. For example, these denote different libraries with different sets of versions and different potential vulnerabilities:

The defined ecosystems are:

It is permitted for a database name (the DB prefix in the id field) and an ecosystem name to be the same, provided they have the same owner who can make decisions the meaning of the ecosystem_specific field (see below).

The severity field is an optional element defined here . This severity field applies to a specific package, in cases where affected packages have differing severities for the same vulnerability. If any package level severity fields are set, the top level severity must not be set.

The affected object’s versions field is a JSON array of strings. Each string is a single affected version in whatever version syntax is used by the given package ecosystem.

When there is no well-defined packaging ecosystem specified (for example, general C/C++ libraries), GIT commit ranges are typically the best way to define vulnerable version ranges. In this case, versions specified in this array cannot be relied upon to conform to any particular syntax (e.g. they could be the upstream Git version tags derived from these GIT commit ranges, which is what OSV.dev populates this field with). In this situation, the GIT commit ranges in affected[].ranges should be used to match vulnerabilities by Git commit hashes.

The affected object’s ranges field is a JSON array of objects describing the affected ranges of versions.

In the ranges field, the type field is required. It specifies the type of version range being recorded and defines the interpretation of the events object’s introduced , fixed , and any type-specific fields.

The defined types and their additional fields are:

SEMVER : The versions introduced and fixed are semantic versions as defined by SemVer 2.0.0 , with no leading “v” prefix. The relation u < v denotes the precedence order defined in section 11 of SemVer 2.0 . Ranges listed with type SEMVER should not overlap: since SEMVER is a strict linear ordering, it is always possible to simplify to non-overlapping ranges.

Specifying one or more SEMVER ranges removes the requirement to specify an explicit enumerated versions list (see the discussion above).

Some ecosystems may recommend using SemVer 2.0 for versioning without explicitly enforcing it. In those cases you should use the ECOSYSTEM type instead.

ECOSYSTEM : The versions introduced and fixed are arbitrary, uninterpreted strings specific to the package ecosystem, which does not conform to SemVer 2.0’s version ordering.

It is recommended that you provide an explicitly enumerated versions list when specifying one or more ECOSYSTEM ranges, because ECOSYSTEM range inclusion queries may not be able to be answered without reference to the package ecosystem’s own logic and therefore may not be able to be used by ecosystem-independent processors. The infrastructure and tooling provided by also provides automation for auto-populating the versions list based on supported ECOSYSTEM ranges as part of the ingestion process.

GIT : The versions introduced and fixed are full-length Git commit hashes. The repository’s commit graph is needed to evaluate whether a given version is in the range. The relation u < v is true when commit u is a (perhaps distant) parent of commit v .

Specifying one or more GIT ranges does NOT remove the requirement to specify an explicitly enumerated versions list, because GIT range inclusion queries cannot be answered without access to a copy of the underlying Git repository.

The ranges object’s events field is a JSON array of objects. Each object describes a single version that either:

These events objects represent a “timeline” of status changes for the affected package.

The values of introduced , fixed , last_affected and limit are version strings as defined by the affected[].ranges[].type field. Note that these version strings are not guaranteed to exactly match versions of the package found in the upstream package repository. For example, they may be normalized, or have build metadata stripped.

Only a single type (either introduced , fixed , last_affected , limit ) is allowed in each event object. For instance, {"introduced": "1.0.0", "fixed": "1.0.2"} is invalid .

Entries in the events array may be “last_affected” or “fixed” events, but not both. It’s strongly recommended to use fixed instead of last_affected where possible, as it precisely identifies the version which contains the fix. last_affected should be thought of as the hard ceiling of the vulnerability at the time of publication in the absence of a fixed version. Versions above last_affected should be considered unaffected. Unfortunately this opens up the possibility for false negatives, which is why fixed is overwhelmingly preferred. An example is available to illustrate the difference.

The fixed and limit events are closely related and involve a similar trade-off for GIT ranges. (See the limit example for details how they differ.) events arrays with fixed events must include all other cherrypicked fix commits in all branches as separate fixed events to avoid false positive matches in other branches. Conversely, limit events restrict the set of vulnerable commits to those reachable from the limit , which may result in false negatives . Where possible, it’s strongly recommended to use fixed over limit .

There must be at least one introduced object in the events array. While not required, it’s also recommended to keep the events array sorted according to the affected[].ranges[].type of the range.

See examples for examples of how to describe affected ranges.

The ranges object’s repo field is the URL of the package’s code repository. The value should be in a format that’s directly usable as an argument for the version control system’s clone command (e.g. git clone ).

The affected object’s ranges field is a JSON array of objects, each describing a single range. The range object defines the fields type , events , repo . introduced , fixed , and additional type-specific fields as needed.

This field is required if affected[].ranges[].type is GIT .

The ranges object’s database_specific field is a JSON object holding additional information the range as defined by the database from which the record was obtained. The meaning of the values within the object is entirely defined by the database and beyond the scope of this document.

Databases should only use this field to store additional context that may be useful in converting from the OSV format back into the original database representation. Values in this field have no effect on the evaluation algorithm .

The affected object’s ecosystem_specific field is a JSON object holding additional information the vulnerability as defined by the ecosystem for which the record applies. The meaning of the values within the object is entirely defined by the ecosystem and beyond the scope of this document.

For example, the Go ecosystem includes here information the affected functions and which modules the packages were found in, along with severity in the Go project-specific severity scale.

Note that this is a single field with key “ecosystem_specific”, which itself contains a JSON object with unspecified fields.

The affected object’s database_specific field is a JSON object holding additional information the vulnerability as defined by the database from which the record was obtained. The meaning of the values within the object is entirely defined by the database and beyond the scope of this document.

In general, the canonical database for a particular ecosystem should record its information in ecosystem_specific , allowing other aggregator databases to put their own summaries in database_specific .

For example, databases that add additional information such as computed CVSS scores for ecosystems that do not provide them could add that information here.

Note that this is a single field with key “database_specific”, which itself contains a JSON object with unspecified fields.

The algorithm to evaluate if a package pkg at version v is vulnerable is given by the IsVulnerable function in the pseudocode below:

The following expresses that “every possible version is affected”.

The following expresses that “everything before 1.0.2 ” is affected.

The following expresses that versions in the SemVer ranges [1.0.0, 1.0.2) or [3.0.0, 3.2.5) are affected. Everything else is unaffected.

limit events are typically not necessary for describing numbered (linear) version ranges and should not be used. They are more useful for git ranges, where it has more implications for the evaluation algorithm. Take the following git commit graph and git range:

Without an explicit limit , the list of computed affected commits will be X, A, B, C, D, E, F . This is the desired behaviour in most cases.

If limit is set to Y , the list of affected commits will be X, A, B, C . This is equivalent to git rev-list X..Y (but including X and excluding Y ). This may be useful if the scope of a vulnerability entry is limited to a small set of linear branches. Multiple limit events may be specified for each branch – each expands the scope of the git commit graph to cover.

Note that we did not specify a fixed event here as limit makes it redundant.

Understanding the difference between last_affected and fixed is essential to identifying where false negatives may occur.

The following example expresses that the vulnerability is present in all versions of the package, up to and including version 2.1.214 . Versions above 2.1.214 are assumed to be free from the vulnerability, but there is a potential for a false negative. The last_affected field is typically assigned at the time of discovery and assumes the vulnerability will be addressed in the following version.

The following example looks similar, but there are differences in how it is interpreted. The vulnerability is present in all versions of the package up to version 2.1.214 . In this case 2.1.214 is not vulnerable. Versions 2.1.214 and above do not include the vulnerability and there isn’t the possibility for false negatives that we see in the last_affected case.

Using fixed is preferable to last_affected whenever possible. The use of fixed requires fewer assumptions and eliminates the possibilities for false negatives.

The references field contains a list of JSON objects describing references. Each object has a string field type specifying the type of reference, and a string field url . The url is the fully-qualified URL (including the scheme, typically “ linking to additional information, advisories, issue tracker entries, and so on the vulnerability itself. The type specifies what kind of reference the URL is.

The known reference type values are:

The credits field is a JSON array providing a way to give credit for the discovery, confirmation, patch, or other events in the life cycle of a vulnerability.

Each of the objects in the credits array must contain at minimum a name field specifying the name of the individual or entity being credited, using whatever notation they prefer. It can also optionally include a JSON array.

credits[].name should specify the name, label, or other identifier of the individual or entity being credited, using whatever notation the creditor prefers. For instance, this could contain a real name like Kovács János , an Internet handle like erikamustermann , an entity name like GitHub , or something else. This field is required for each credits entry.

Each credits[]. [] entry should be a valid, fully qualified, plain-text URL at which the credited can be reached. Providing contacts is optional.

The optional credits[].type field should specify the type or role of the individual or entity being credited. It must be one of the following defined credit types:

These values and their definitions correspond directly to the credit types defined in the MITRE CVE specification .

Including a URL and an email address in credits[]. [] and a credit type:

The top-level database_specific field is a JSON object holding additional information the vulnerability as defined by the database from which the record was obtained. The meaning of the values within the object is entirely defined by the database and beyond the scope of this document.

Unlike the affected[].database_specific field which is specific to each affected product, this top-level field allows aggregator databases to add custom data that they considered applicable to the whole vulnerability.

Note that this is a single field with key “database_specific”, which itself contains a JSON object with unspecified fields.

The Go vulnerability database uses this format. See for example entries and details of ecosystem_specific fields.

GitHub uses this format already for its vulnerabilities. Here is the encoding of one entry:

OSV uses this format already for its vulnerabilities. Here is the encoding of one entry:

The Rust advisory DB exports this format. Here’s an example entry:

Python currently has a community vulnerability database using this format. Here is a potential encoding of a vulnerability entry.

Debian security advisory (DSA) does not use this format currently, but using the conversion tool , the DSA can be converted into the OSV format.

Ruby does not use this format currently, but here is a potential translation of one Ruby advisory:

We don’t yet have a GHC vulnerability, but it would look like the following one (similar to the Hackage example, but changing ecosystem to "GHC" ):

R currently has a community vulnerability database using this format. Here is an example encoding of a vulnerability entry.

When a package in the Android ecosystem is the Linux kernel source code, its name will be :linux_kernel: , optionally appended with one of the following SoC vendor names indicating applicability of the vulnerability to kernels of that particular vendor:

Extracted Entities

CVEs (1)

Domains (1)