Caution
The advisories here are in testing, are not valid, and will be deleted. Do not import any advisories with the DONOTUSEJLSEC-
prefix.
Warning
Work in progress. Likely incorrect and definitely incomplete data.
There are four key goals of this repository:
- Be a database of security advisories that pertain to packages in the Julia ecosystem.
- Provide the structure for authoring, reviewing, and maintaining these security advisories.
- Export the security advisories in standard format for downstream consumers.
- Provide tooling to search, identify, and import applicable security advisories (both upstream and aliasing) from multiple independent advisory databases.
Security advisories against packages in the Julia General registry are published in the advisories/published
directory of this repository, grouped by year, with filenames corresponding to their uniquely assigned identifier. All published advisories have an identifier of JLSEC-YYYY-nnn
, and are stored as Markdown files with a TOML "front-matter" section with structured metadata.
With a few important exceptions, these fields correspond exactly (including the schema_version
!) to their definitions in the Open Source Vulnerability (OSV) format. The exceptions are:
- The
summary
is the first Markdown section after the TOML frontmatter (if it's a header). - The
details
are the remainder of the file. - The
affected
packages are stored much more succinctly as just an array of tables with each package's name (pkg
) and vulnerableranges
. The ranges themselves are vectors of strings, using GitHub's vulnerable version range (VVR) syntax. - Timestamps are stored directly as TOML datetimes, not as strings.
- Credits support an optional shorthand
"author <[email protected]>"
string format for the common cases where no credit type is assigned and there is only one email-based contact method. - References support an optional shorthand string format to just contain the URL itself for the default
"WEB"
reference type. - Severities similarly support an optional shorthand string format that contains just CVSS vector itself.
- Fields with names starting with
jlsec_
are placed intodatabase_specific
(the the prefix removed).
In practice, a valid JLSEC advisory looks like this:
```toml
schema_version = "1.7.3"
id = "JLSEC-2025-1"
modified = 2025-09-23T02:23:16.095Z
published = 2025-09-23T02:23:16.095Z
aliases = ["GHSA-4g68-4pxg-mw93", "CVE-2025-52479"]
[[affected]]
pkg = "HTTP"
ranges = ["<= 1.10.16"]
[[affected]]
pkg = "URIs"
ranges = ["< 1.6.0"]
[[jlsec_sources]]
html_url = "https://github.com/JuliaWeb/HTTP.jl/security/advisories/GHSA-4g68-4pxg-mw93"
id = "GHSA-4g68-4pxg-mw93"
imported = 2025-09-23T02:06:09.198Z
modified = 2025-06-24T23:01:25Z
published = 2025-06-24T23:01:25Z
url = "https://api.github.com/repos/JuliaWeb/HTTP.jl/security-advisories/GHSA-4g68-4pxg-mw93"
```
# CR/LF injection in URIs.jl (also affects HTTP.jl)
### Description
The URIs.jl and HTTP.jl packages allowed the construction of URIs containing CR/LF characters. If user input was not otherwise escaped or protected, this can lead to a CRLF injection attack.
New JLSEC advisories are published through a typical pull request process on this repository. Create a new advisory Markdown file in the appropriate advisories/published/$year
directory. A an advisory filename that begin with JLSEC-0000
will automatically be re-named to the next available identifier immediately (and automatically) after merging, and its id
will correspondingly be updated. All timestamps will similarly be updated after merging to reflect the time at which the advisory was available. CI will ensure the TOML is valid and can be exported to a valid OSV.
Once published, an advisory shall not be deleted. If it is determined to have been published in error, instead its withdrawn
date should be set.
A particular advisory identifier may be reserved by creating an empty file in advisories/reserved/
with the reserved ID.
All fields (other than the id
and published
timestamp) may be edited through subsequent pull requests; the updated time will be appropriately set after merging.
JLSEC advisories that correspond to advisories in other databases should take care to appropriately set their alias
, upstream
, and related
fields.
All advisories in the advisories/published
folder are automatically exported to JSON files grouped by year in valid OSV schema on the generated/osv
branch. Pull request CI does a dry-run of this conversion and validation before merging.
The code in this repository aims to help create and manage these advisories, using several upstream data sources. The upstream data here is... challenging. There are several key data sources:
- MITRE's CVEs: while these IDs are the unique and canonical identifiers for any major vulnerability, the reports themselves are largely unstructured text and may be of varying quality and may be disputed. They may or may not have structured information about the software vendor and product, and even versioning information may be missing or lacking. A good example is CVE-2021-4048.
- NIST's NVD: The National Vulnerability Database takes CVEs and enriches them with additional metadata — most importantly the CPE (Common Platform Enumeration) identifier. The above CVE-2021-4048 in NVD adds structured identifiers for OpenBLAS (
cpe:2.3:a:openblas_project:openblas:…
) and Julia itself (cpe:2.3:a:julialang:julia:…
) with very specific version information attached. This enrichment step often lags behind the initial CVE publication by many months. - ENISA's EUVD: Tracks nearly all CVEs with their own independent identifier (and maybe also advisories from other ecosystems). They also enrich advisories (I think mostly cribbing from CISA's vulnrichment), but do not use CPEs. Instead, they have unstructured vendor, product, and version fields. That version field is sometimes obviously parse-able (e.g.,
1.2.0 < 1.2.3
), but often is freetext (Fixed in libfoo 1.2.3 (Affected 1.2.0,1.2.1,1.2.2)
or1.0.2 through 1.0.2h
orAll 1.0.2
or ...). Their vendor and product are often populated more rapidly than NVD's CPE. Their summary and details are often qualitatively worse than NVD's. - GitHub's GHSA: GitHub Security Advisories have their own identifiers and may or may not have a CVE alias. Some GHSAs are "orginated" by GitHub, but most are imported from NVD. Note that there are three flavors of GHSAs:
- There are the advisories available in their advisory database at
github.com/advisories
. These are not all the GHSAs!- Some GHSAs in this database are GitHub reviewed, tagged with a specific package, package metadata, and an ecosystem. Julia is not (yet!) a reviewed ecosystem. Cf. github/advisory-database#1689.
- Some GHSAs in this database are not reviewed, but are still accessible at
/advisories
and via API. These are mostly (maybe entirely?) CVEs that were automatically imported from upstream advisory databases (maybe just NVD?).
- There are advisories published on a repository. These also have
GHSA-xxxx-xxxx-xxxx
ids. You can request GitHub review and GitHub can — as a CVE Numbering Authority — assign and publish a corresponding CVE if appropriate. However, even with that review step, this GHSA will not be available at/advisories
if not part of a reviewed ecosystem (see above)! They are not available via API unless you specifically ask for the security advisories at a particular repository. Without being a part of a reviewed ecosystem, the affected product and version fields are unrestricted plain text. A good example is GHSA-4g68-4pxg-mw93, which is on HTTP.jl's repository, names both HTTP and URIs as vulnerable, and has a CVE that was assigned by GitHub staff. The corresponding CVE-2025-52479 has not yet been enriched by the NVD and has no structured information about the packages in the report. It's also worth noting that GitHub's/advisories
database did not import that CVE from NVD.
- There are the advisories available in their advisory database at
- JuliaRegistries/General: The Pkg registry provides the available package names along with their available versions and upstream repository.
- Every package's source code and dependency graph. All Julia dependencies are tracked in a first-class manner through Pkg and the
Manifest.toml
, but a Julia package might also ship non-Julia code. We need to identify these upstream components; they are not tracked in the Manifest. There are four possible ways in which these upstream components might be provided:- As a JLL built by BinaryBuilder and a build script in Yggdrasil. These packages are easy to identify (they end in
_jll
!) and are the canonical way to bundle upstream components today. There is (not yet) structured metadata about these components. JLLs built with BinaryBuilder v0.2.5+ (after June 2020) have a Sources section in their README that lists URLs from which sources were downloaded — often including their version numbers. Prior to this, (roughly August 2019-June 2020), this information is best found by correlating against build scripts themselves. A good example is [email protected]+0. Its README logged that it downloaded and builtcairo-1.18.4.tar.xz
(downloaded from cairographics.org), and it provides that binary as an Julia Artifact pointing to its release (v1.18.5+0) assets. Versions at [email protected]+5 and prior do not have this logged. To identify prior versions, we'd need to correlate against the (likely) Yggdrasil build script. - Prior to JLLs, BinaryProvider was briefly used. They used
deps/build.jl
scripts in the higher-level Cairo.jl package to gather artifacts from the_jll
repositories. Early in BinaryProvider's evolution, they did not list the JLLs in the Project/Manifest, but later they did. See, e.g., [email protected] and [email protected]. - Prior to BinaryProvider, BinDeps was largely used. Here, the
deps/build.jl
went out to all the various package managers (WinRPM, Homebrew, apt-get, yum) to get the built binaries — or it did a wholesale from-source build. See [email protected], which provided not just Cairo, but all its dependencies, too. - It is also possible that
deps/build.jl
was (ab)used in other ways, too. - It is also possible that
Artifacts.toml
downloads arbitrary executables.
- As a JLL built by BinaryBuilder and a build script in Yggdrasil. These packages are easy to identify (they end in
There are hundreds of thousands of GitHub advisories and CVEs. The GitHub actions on this repository aim to find new vulnerabilities that have been registered, affect Julia packages, and automatically open pull requests suggesting thier inclusion in this database. The biggest challenge is in accurately identifying the relevant package(s) and version(s).
There are four categories of advisory that we need to handle:
- Advisories first published here. Advisories can be published here directly via pull request. Subsequent advisories may be created in other databases; these should then later be added as
alias
es. - Advisories published on a registered package's GitHub repository. A GitHub-based package maintainer can create a new GHSA security advisory directly against the canonical (registered) package repository. The versions listed within this GHSA directly corresponds to the registered and vulnerable, and the JLSEC here must have this GHSA listed as one of its
alias
es. - Independently-issued advisories:
- discussing or affecting a Julia package. Any of the advisory databases listed above might publish an advisory with a Julia package mentioned or explicitly listed as
affected
. Thanks to the convention of discussing packages asPackage.jl
, this can be fairly accurately targeted, even within freetext descriptions. The versions here (if there are any) correspond directly against the registered versions of the Package, and the independently-issued advisory must be listed as analias
. - pertaining to an upstream package that a Julia package bundles. There are two challenges here; we first must know what upstream projects the Julia packages bundle (and precisely which upstream versions a given Julia package version included), and then even when we know that, we need to be able to conclusively identify those upstream projects in these other advisory databases. The versions listed in this independently-issued advisory are arbitrary and dependent upon the upstream project itself, making range comparisons fraught. Because the newly issued JLSEC corresponding to this advisory contains novel version information these advisories must be listed as
upstream
.
- discussing or affecting a Julia package. Any of the advisory databases listed above might publish an advisory with a Julia package mentioned or explicitly listed as
In addition to the periodic check, NVD, EUVD, and GitHub all support fetching all advisories for a specific CPE or repository, respectively. They also support fetching a single CVE or repository at a time.
So the GitHub actions here:
- Run some basic unit tests of the Julia
src
functionality - Automatically update ids, timestamps, export to OSV, and validate that OSV. This is run upon merges to main, and also dry-run on pull requests.
- Search upstream advisory databases for potentially relevant advisories, opening pull requests to import them. Finding relevant advisories to JLL packages is done based upon its components (store in the
package_components.toml
file) - Automatically update the
package_components.toml
file by looking through the JLL's sources (injll_metadata.toml
) and finding download URLs and repositories that match an upstream project (manually populated inupstream_project_info.toml
) - Automatically evaluates Yggdrasil's build scripts to update the
jll_metadata.toml
file.