Basilisk
Architecture

How matching works

How Basilisk joins package identities to advisories and evaluates affected versions.

There are two matchers. One connects PURLs to OSV affected entries. The other connects CPE identities to NVD configurations. Both compare the advisory data with versions published on conda-forge.

The matchers do not try to decide whether a vulnerability is exploitable in your environment. They answer a smaller question: is a known conda-forge version inside the range reported by the advisory source?

For NVD, an active Anchore configuration replacement supplies the effective affected ranges. It replaces the entire original configuration set rather than adding ranges to it. Removing the enrichment restores original applicability. The original NVD metadata remains intact, and the evidence identifies Anchore and its pinned source revision.

Missing, unprojected, or unsupported applicability is not evidence that a package is unaffected. Unsupported CPE logic with a known package identity stays indeterminate. CNA affected data is retained but is not directly matched.

A match is not a verdict

An evaluated package–advisory match means a known version matches reported affected versions or ranges. Runtime configuration, patches applied by a conda-forge build, and whether vulnerable code is reachable are not evaluated yet.

The version universe

Repodata ingestion retains individual conda artifacts, including their subdir, build string, build number, filename, and available hashes. The matcher combines their distinct version strings across all subdirs into one list.

Unqualified matching uses that shared version list. Qualified NVD criteria add platform-specific range membership against immutable artifact snapshots; they never become a package-wide positive. Build selectors identify exact published artifacts, but do not establish whether a rebuild was patched. An upstream version-range match can therefore remain visible for a backported conda-forge build.

Basilisk also assumes that a conda-forge version maps to the same upstream version. The affected-version set keeps the original repodata string.

OSV and PURLs

The osv-purl matcher considers primary and alternative PURLs from purl-associator.

First, the identity and OSV entry need to belong to the same ecosystem. An npm advisory cannot match a PyPI identity just because both packages have the same name.

Names are normalized before the join:

  • PyPI names use PEP 503 normalization: lowercase, with runs of -, _, and . treated as the same separator.
  • Other ecosystem names are lowercased.
  • GitHub repository URLs are lowercased, normalized to HTTPS, and stripped of a trailing .git.

After the identity joins an affected entry, the matcher checks its ranges and explicit version list.

Version comparators

Version rules differ between ecosystems, so Basilisk picks the comparator from the PURL type:

IdentityComparator
PyPIPEP 440
crates.io, npm, RubyGemsSemantic Versioning
GitHub, CRAN, and other fallback casesconda version ordering
NVD CPE rangesconda version ordering

The result records which comparator was used. If that comparator cannot parse a bound, Basilisk does not quietly treat it as open-ended.

OSV range events

OSV stores ranges as events. Basilisk sorts them with the selected comparator and checks each known conda-forge version.

  • introduced opens an affected interval.
  • fixed closes it and is not itself affected. The interval is [introduced, fixed).
  • last_affected closes the interval after that version, so last_affected itself is included. It does not identify a fixed version or establish that a fix was released.
  • introduced: "0" means there is no lower bound.
  • Explicit versions are matched against the version strings in the conda-forge universe.

Worked example: an OSV fixed event

This example uses a PyPI identity, so the matcher selects PEP 440.

The package identity and known conda-forge versions are:

{
  "identity": "pkg:pypi/pillow",
  "versions": ["9.1.0", "10.1.0", "10.2.0"],
  "latest": "10.2.0"
}

The OSV affected entry has an unbounded start and a fix at 10.2.0:

{
  "package": { "ecosystem": "PyPI", "name": "Pillow" },
  "ranges": [{
    "type": "ECOSYSTEM",
    "events": [
      { "introduced": "0" },
      { "fixed": "10.2.0" }
    ]
  }]
}

An advisory can contain several ranges or affected entries. Basilisk combines the versions found through all entries for the same package, advisory, and identity.

Git commit ranges cannot usually be compared to release versions. If an entry only has a GIT range and no explicit versions, the identity match is kept as unevaluated rather than dropped.

NVD and CPEs

The nvd-cpe matcher joins package CPEs to NVD criteria using the lowercase (vendor, product) pair. It only considers application CPEs (part = a) marked vulnerable: true.

For each matching criterion:

  • Inclusive and exclusive bounds are checked against the conda-forge versions.
  • A concrete version inside the CPE is treated as an exact version under the comparator.
  • A wildcard version without bounds cannot be narrowed to specific versions.

The last case becomes version_unbounded and retains every known version as a candidate. That stored membership does not establish an evaluated range match for any version or platform.

Worked example: an NVD upper bound

{
  "criteria": "cpe:2.3:a:zlib:zlib:*:*:*:*:*:*:*:*",
  "versionEndIncluding": "1.2.12",
  "vulnerable": true
}

If the CPE used * for the version and had no bounds, the result would be version_unbounded with all three versions.

Platform conditions

Supported CPE target_hw and target_sw values constrain the artifact's conda subdirectory. Hardware and software intersect: arm64 plus linux selects linux-aarch64. Version bounds are evaluated only after that platform matches. Unknown hardware, unsupported non-platform fields, missing artifact evidence, and a constrained noarch artifact without an execution environment remain indeterminate. Unrecognized software values such as python are retained in the raw criterion but ignored as execution-platform constraints.

Qualified positives remain platform-dependent in a version-only view, even if all currently observed artifacts match. A platform excluded by a criterion is not a claim that the package is safe from all advisories. Missing or stale evidence cannot establish an unaffected result.

The explorer's Result column shows whether the listed versions match the advisory's affected range on those platforms. Versions and platforms with identical results share a row. All platforms means current, complete evidence reports affected versions without a platform restriction. All indexed platforms means the full indexed artifact inventory agrees for the listed versions; it does not remove the source's platform conditions. Truncated inventory previews cannot establish that agreement. Unknown and mixed build results keep explicit platform names, and freshness and completeness remain visible. Source-reported affected platforms absent from the artifact preview remain visible separately; the preview does not replace that evidence.

Build details are collapsed by default. An explicitly queried artifact and its platform stay visible even when the artifact falls outside the inventory preview. Other builds and their provenance remain expandable. Platform grouping does not establish patch or backport status.

An artifact subdir describes where it runs, not what a compiler generates. CVE-2023-4039 concerns GCC targeting AArch64 under specific stack-protector and program conditions. Basilisk retains that AArch64 condition, but does not infer a compiler target from its package name, build string, or host subdir. The qualified result stays indeterminate until the required target and usage evidence is available.

Build patches and backports

A higher build number is not proof of a security fix. Current machine results describe source-range applicability independently of patch status; without authoritative evidence, build patch status is unknown.

Future build decisions require exact artifact identity and checksum, retained evidence, an authorized decision, and its producing operation. A feedstock patch must be connected to the rendered build output and published checksum; a merged recipe change alone is insufficient. Supplier assertions also need an accepted issuer and exact product scope.

These decisions can distinguish affected and fixed builds of the same version without changing the upstream range. They must not propagate a fix to other builds, platforms, or replacement bytes. Conflicting authoritative evidence remains unknown until explicitly resolved. Build-decision storage and approval belong to later curation work, not the current platform matcher. Repodata ingestion and matching download metadata only, never package archives.

Deciding applicability

Each match gets one of three applicability values:

ValueWhen it is used
evaluatedAt least one known conda-forge version matched an OSV range, explicit version, or bounded NVD criterion.
unevaluatedThe identity joined, but the available OSV version information could not be evaluated. Common examples are GIT-only ranges and invalid range bounds.
version_unboundedAn NVD CPE matched the vendor and product but provided no usable version bounds.

If a range is valid and none of the known versions fall inside it, no match is written.

Applicability and identity confidence are separate. A range can be fully evaluated even when the package identity is still automatic or unverified.

What the API returns

The OSV-compatible query endpoints return evaluated matches by default. Add ?confidence=low to include unevaluated and version_unbounded matches.

Each result can include:

  • the affected conda-forge versions,
  • whether the latest known version is in that set,
  • the comparator,
  • the matched PURL or CPE,
  • identity status,
  • matcher name and version.

active_on_latest uses exact membership in the affected-version set. It does not compare or normalize the latest version a second time.

On this page