Skip to main content

Overview

VerifyGitHubVulnerabilities is a recurring, read-only monitoring job that ensures the NuGet Gallery’s vulnerability data stays in sync with GitHub’s Security Advisory Database. It fetches every advisory tagged for the NUGET ecosystem via GraphQL, then walks through the same ingestion pipeline used by GitHubVulnerabilities2Db — but instead of writing to the database it compares what should be there against what is there and logs errors for every mismatch.
This job is intentionally side-effect-free. It opens the Gallery database in read-only mode and never writes to SQL, Azure Blob Storage, or any other persistent store. Its only outputs are structured log entries and Application Insights metrics.
The two verification passes are independently toggleable:
  • Database verification — checks that every advisory exists in the PackageVulnerabilities table with the correct severity, advisory URL, and per-version VulnerablePackageRanges linkage.
  • Registration metadata verification — fetches NuGet V3 registration blobs for each affected package and confirms that every version in a vulnerable range carries the correct vulnerabilities array, and that no out-of-range version is incorrectly tagged.

GitHubVulnerabilities2Db

Sibling job that actually ingests GitHub advisories into the Gallery SQL database. VerifyGitHubVulnerabilities reuses its GraphQL query layer and ingestion pipeline but substitutes a verifying visitor for the writer.

NuGet Gallery (Web)

Consumes the vulnerability records that this job monitors. Discrepancies reported here indicate that package detail pages or V3 feeds may be serving incorrect security data.

GitHub Security Advisory API

Authoritative source of truth. Queried in full on every run (since epoch) using the same GraphQL query as the ingest job.

NuGet V3 Registration Blobs

The second verification target. The job uses NuGet.Protocol to download package metadata and inspect the embedded vulnerability arrays directly from CDN-served blobs.

Key Files and Classes


Dependencies

Internal Project References

NuGet / Framework Dependencies (resolved transitively)


Notable Patterns and Implementation Details

Dual-registration pattern for the verifier. PackageVulnerabilitiesVerifier is registered in Autofac as both IPackageVulnerabilitiesManagementService (the interface the ingestion pipeline calls) and IPackageVulnerabilitiesVerifier (the interface the job checks for HasErrors). The SingleInstance() lifetime ensures the same object accumulates errors across the entire advisory set before Job.Run inspects it.
Full advisory scan on every run. Unlike incremental ingestion jobs, GetAdvisoriesSinceAsync is called with DateTimeOffset.MinValue, meaning the entire GitHub NuGet advisory corpus is fetched and verified on every execution. This is intentional — the goal is a complete consistency check, not delta processing.
Withdrawn advisory check is DB-only. The job explicitly skips registration-metadata verification for withdrawn advisories. Verifying withdrawals in metadata would require downloading every package/version blob to confirm absence — impractical at scale. Database coverage is considered sufficient for withdrawn entries.
ApplyExistingVulnerabilitiesToPackage is not implemented. This method from IPackageVulnerabilitiesManagementService throws NotImplementedException. It is never called during normal verification flow; the interface is implemented solely to satisfy the shared ingestion pipeline contract.
Thread-safe metadata caching via SemaphoreSlim. PackageVulnerabilitiesVerifier fans out verification tasks concurrently per advisory but serializes V3 metadata fetches with a static SemaphoreSlim(1) and a Dictionary cache keyed on packageId. This avoids redundant HTTP calls when multiple advisories affect the same package while remaining safe under Task.WhenAll parallelism.
Incoming package ID whitespace. GitHub advisory data can include leading or trailing spaces in package IDs. The verifier trims these (range.PackageId.Trim(' ')) before grouping ranges for metadata verification, preventing phantom cache misses and false-positive error reports.

Running Locally

Minimal appsettings.json:
The Microsoft Entra ID client certificate for the app registration must be installed in the CurrentUser certificate store before running. Key Vault secrets (including the GitHub PAT) are resolved at startup via managed identity or the installed certificate.