OSV.dev Integration for CVE Lookups in SkillSpector: Implementation Guide

SkillSpector integrates OSV.dev by querying the batch API endpoint with package metadata, implementing an in-memory cache with 1-hour TTL, and falling back to static vulnerability databases when the service is unreachable.

NVIDIA's SkillSpector performs real-time vulnerability detection through its OSV.dev integration for CVE lookups in Python and JavaScript dependencies. The implementation resides in skillspector/nodes/analyzers/osv_client.py and provides the supply-chain analyzer with live security intelligence while maintaining offline resilience.

How the OSV Client Module Works

The osv_client.py module encapsulates all communication with the OSV.dev API. It handles request construction, response parsing, severity calculation, and network failure recovery.

Step 1: Package-Level Request Generation

For each dependency, the analyzer builds a JSON query containing the package name, optional version, and ecosystem identifier. The helper function _build_query constructs these payloads for "PyPI" or "npm" ecosystems.

According to the source code, the query structure includes the package name, version string, and ecosystem constant (ECOSYSTEM_PYPI or ECOSYSTEM_NPM) before being aggregated into a batch request.

Step 2: In-Memory Caching Strategy

Before issuing network requests, the client checks an in-process cache keyed by the tuple (name, version, ecosystem). Cached entries persist for one hour as defined by _CACHE_TTL_SECS = 3600.

The internal methods _get_cached and _put_cache manage cache look-ups and updates. This minimizes redundant API calls when analyzing multiple files containing overlapping dependencies during the same process run.

Step 3: Batch API Request

All uncached queries are sent in a single POST request to https://api.osv.dev/v1/querybatch (stored in _OSV_BATCH_URL). The query_batch function orchestrates this request and parses the response, which contains a list of vulnerability IDs for each submitted package.

This batch approach reduces network overhead by consolidating multiple package lookups into one HTTP transaction rather than issuing individual requests per dependency.

Step 4: Vulnerability Detail Fetching

For each vulnerability ID returned by the batch query, the client issues a GET request to https://api.osv.dev/v1/vulns/<ID>. To prevent latency issues, the implementation limits detail fetching to the first 10 IDs per package.

The _fetch_vuln_details helper parses the JSON response into VulnResult objects. These objects contain:

  • vuln_id: The OSV vulnerability identifier
  • summary: Human-readable description
  • severity: Calculated severity level
  • aliases: Associated CVE numbers and other identifiers

Step 5: Severity Estimation Without External Dependencies

OSV vulnerability objects may contain explicit severity fields or raw CVSS vectors. When only a CVSS vector is present, the _estimate_cvss_severity function estimates a coarse severity band (CRITICAL, HIGH, MEDIUM, LOW) without importing full CVSS calculation libraries.

This lightweight estimation avoids heavy dependencies while still providing actionable risk categorization for the supply-chain analyzer.

Step 6: Graceful Fallback Handling

If the OSV request fails due to network errors, timeouts, or air-gapped environments, query_batch returns empty result lists. The supply-chain analyzer then falls back to built-in static vulnerability databases (_FALLBACK_VULNERABLE_PYPI and _FALLBACK_VULNERABLE_NPM).

Additionally, the is_available() method performs a lightweight POST with a dummy query to verify OSV endpoint reachability before attempting full batch requests, preventing unnecessary timeouts during analysis.

Integration with the Supply-Chain Analyzer

The static_patterns_supply_chain.py analyzer orchestrates the OSV integration by:

  1. Extracting dependency entries from requirements.txt, pyproject.toml, setup.py, Pipfile, or package.json
  2. Calling query_batch with lists of (name, version) tuples and the appropriate ecosystem constant
  3. Creating SC4 findings for vulnerable packages that include the most severe result and formatted advisory IDs via _format_vuln_ids
  4. Processing uncovered packages through the static fallback routine (_sc4_from_fallback) when OSV is unavailable

Practical Usage Examples

You can interact with the OSV client directly for custom vulnerability scanning:

from skillspector.nodes.analyzers.osv_client import (
    ECOSYSTEM_PYPI,
    ECOSYSTEM_NPM,
    query_batch,
    is_available,
)

# 1️⃣ Check that the OSV.dev service is reachable

if is_available():
    # 2️⃣ Build a list of (package, version) tuples

    packages = [
        ("requests", "2.28.0"),   # PyPI package

        ("lodash", "4.17.20"),    # npm package

    ]

    # 3️⃣ Query the OSV.dev batch endpoint for PyPI packages

    results = query_batch(packages, ECOSYSTEM_PYPI)

    # 4️⃣ Inspect the returned VulnResult objects

    for pkg, vulns in zip(packages, results):
        name, version = pkg
        if not vulns:
            print(f"{name} ({version}) – no known CVEs")
            continue

        print(f"{name} ({version}) – {len(vulns)} CVE(s) found:")
        for v in vulns:
            print(f"  • {v.vuln_id} – {v.summary[:80]} (severity={v.severity})")
else:
    print("OSV.dev endpoint not reachable – falling back to static data")

In the supply-chain analyzer, this logic executes automatically:


# Inside static_patterns_supply_chain.py

pkg_pairs = [(name, version) for name, version, _ in packages]
osv_results = query_batch(pkg_pairs, ecosystem)   # ← live OSV lookup

# Each `osv_results` entry is a list[VulnResult] used to build SC4 findings.

Key Implementation Files

Summary

  • Batch API Architecture: SkillSpector consolidates vulnerability lookups into single POST requests to https://api.osv.dev/v1/querybatch to minimize network overhead.
  • Intelligent Caching: The in-memory cache with 1-hour TTL prevents redundant API calls for repeated dependency checks during the same analysis run.
  • Dual Ecosystem Support: The implementation handles both PyPI and npm packages through ecosystem-specific constants and query builders.
  • Resilient Fallback: When OSV.dev is unreachable, the system automatically reverts to static vulnerability databases (_FALLBACK_VULNERABLE_PYPI/_FALLBACK_VULNERABLE_NPM).
  • CVSS Parsing: Custom severity estimation logic avoids heavy dependencies while categorizing risks into standard severity bands.

Frequently Asked Questions

How does SkillSpector handle network failures during OSV lookups?

If the OSV.dev API is unreachable due to network errors, timeouts, or air-gapped environments, the query_batch function returns empty result lists. The supply-chain analyzer detects these empty results and automatically falls back to static vulnerability databases containing known vulnerable packages for PyPI and npm.

What information does SkillSpector cache from OSV.dev responses?

The OSV client caches VulnResult objects keyed by the tuple (package_name, version, ecosystem) for 3600 seconds (one hour). Each cached entry contains the vulnerability ID, summary, severity level, and any CVE aliases retrieved from the API, eliminating redundant network requests for duplicate dependencies.

Why does SkillSpector limit vulnerability detail fetching to 10 IDs per package?

The _fetch_vuln_details function limits detail retrieval to the first 10 vulnerability IDs to prevent excessive latency when processing packages with numerous historical vulnerabilities. This prioritization ensures rapid analysis while still capturing the most relevant recent security issues.

Which dependency file formats does the supply-chain analyzer scan for OSV queries?

The supply-chain analyzer extracts dependency information from requirements.txt, pyproject.toml, setup.py, Pipfile for Python projects, and package.json for Node.js projects. It normalizes these entries into (name, version) tuples before submitting them to the OSV batch API with the appropriate ecosystem identifier.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →