# How SkillSpector Performs OSV.dev Live Vulnerability Lookups for Supply Chain Security

> SkillSpector secures your supply chain by performing live OSV.dev vulnerability lookups. It batches queries, calls the OSV.dev API, and normalizes findings with offline fallbacks. Learn how it works.

- Repository: [NVIDIA Corporation/SkillSpector](https://github.com/NVIDIA/SkillSpector)
- Tags: how-to-guide
- Published: 2026-06-22

---

**SkillSpector performs live OSV.dev vulnerability lookups by batching dependency queries, sending POST requests to the OSV.dev API, and normalizing results into severity-scored findings with automatic fallback to static lists when offline.**

NVIDIA's SkillSpector implements real-time supply chain security scanning by integrating OSV.dev live vulnerability lookups directly into its static analysis pipeline. The system queries the Open Source Vulnerabilities database to identify known security issues in Python and JavaScript dependencies, providing immediate feedback during code review. This implementation ensures developers receive current vulnerability data while maintaining resilience through offline fallback mechanisms.

## Building Batched Queries for OSV.dev

The process begins in [`src/skillspector/nodes/analyzers/osv_client.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/osv_client.py) where the `query_batch` function constructs optimized batch requests. For each dependency file discovered in the project, SkillSpector extracts `(name, version)` tuples and maps them to specific ecosystem constants—`ECOSYSTEM_PYPI` for Python packages or `ECOSYSTEM_NPM` for Node.js dependencies.

### Request Structure

Each package translates into a dictionary following OSV.dev's batch specification: `{ "package": {"name": <name>, "ecosystem": <ecosystem>}, "version": <version> }`. The helper function `_build_query` assembles these into a single JSON payload capable of querying multiple packages in one HTTP request, minimizing network overhead when analyzing large dependency trees.

## Executing Live Lookups Against the OSV.dev API

The `query_batch` function transmits requests via `httpx.Client` to `https://api.osv.dev/v1/querybatch`. The client respects the `SKILLSPECTOR_OSV_TIMEOUT` environment variable for configurable network timeouts, ensuring scans don't hang in restricted network environments.

### Retrieving Detailed Vulnerability Records

When OSV.dev returns a `results` array containing vulnerability IDs (`vulns`), SkillSpector initiates secondary GET requests to `https://api.osv.dev/v1/vulns/<id>` via `_fetch_vuln_details`. This retrieval is capped at 10 IDs per batch to prevent API rate limiting while gathering complete severity metadata and advisory summaries.

## Normalizing Severity and Caching Results

Raw vulnerability data transforms into structured `VulnResult` dataclasses through severity normalization pipelines in [`osv_client.py`](https://github.com/NVIDIA/SkillSpector/blob/main/osv_client.py).

### Severity Extraction

The `_severity_from_vuln` function extracts CVSS scores from OSV.dev responses, passing them to `_estimate_cvss_severity` to normalize ratings into standardized severity levels. This ensures consistent risk scoring across different vulnerability databases and advisory formats.

### In-Memory Caching

To optimize repeated scans, [`osv_client.py`](https://github.com/NVIDIA/SkillSpector/blob/main/osv_client.py) maintains an in-memory `_cache` dictionary keyed by `(name, version, ecosystem)` tuples with a one-hour TTL. Subsequent lookups for identical dependencies return cached results, eliminating redundant API calls during iterative development.

## Integrating OSV.dev Results into Supply Chain Analysis

The supply chain analyzer in [`src/skillspector/nodes/analyzers/static_patterns_supply_chain.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/static_patterns_supply_chain.py) orchestrates the vulnerability detection workflow through the `_sc4_from_osv` function.

### Converting to AnalyzerFindings

Each vulnerability list transforms into an `AnalyzerFinding` with human-readable descriptions formatted as: *"Known Vulnerable Dependency: requests==2.31.0 — 1 advisory(ies): CVE-2023-32681 (header leak on redirect)"*. These findings include the normalized severity extracted earlier and precise file locations within the dependency manifest.

### Offline Fallback Mechanism

When network requests fail—the OSV.dev service is unreachable, timeouts occur, or in air-gapped environments—the system sets `_last_query_ok = False` and automatically falls back to `_FALLBACK_VULNERABLE_PYPI` or `_FALLBACK_VULNERABLE_NPM` static lists. A warning finding alerts users that results derive from offline data only, maintaining security visibility despite connectivity issues.

## Implementation Examples

### Direct OSV Client Usage

```python
from skillspector.nodes.analyzers.osv_client import query_batch, ECOSYSTEM_PYPI

# Look up a few PyPI packages

packages = [("requests", "2.31.0"), ("jinja2", "3.1.3")]
results = query_batch(packages, ECOSYSTEM_PYPI)

for pkg, vulns in zip(packages, results):
    print(f"{pkg[0]}=={pkg[1]} → {len(vulns)} vulnerabilities")
    for v in vulns:
        print(f"  • {v.vuln_id} – {v.severity}: {v.summary}")

```

### Full Supply Chain Node Execution

```python
from skillspector.state import SkillspectorState
from skillspector.nodes.analyzers.static_patterns_supply_chain import node

# Minimal state containing a requirements file

state = SkillspectorState({
    "components": ["requirements.txt"],
    "file_cache": {"requirements.txt": "requests==2.31.0\njinja2==3.1.3"},
    "manifest": {}
})

response = node(state)
for finding in response["findings"]:
    print(f"[{finding.rule_id}] {finding.message} (severity={finding.severity})")

```

## Checking OSV.dev Availability

The `is_available()` method performs a lightweight POST check to verify OSV.dev reachability before executing full scans. After any query attempt, `was_osv_reachable()` returns the `_last_query_ok` flag, allowing downstream components to adjust behavior based on live connectivity status.

## Summary

- **SkillSpector batches dependency queries** in [`osv_client.py`](https://github.com/NVIDIA/SkillSpector/blob/main/osv_client.py) to minimize API calls to `https://api.osv.dev/v1/querybatch`
- **Vulnerability details are retrieved** via `_fetch_vuln_details` with rate limiting protection (10 IDs per batch)
- **Severity normalization** uses `_severity_from_vuln` and `_estimate_cvss_severity` for consistent risk scoring
- **A one-hour TTL in-memory cache** prevents redundant network requests for repeated dependency scans
- **Offline fallback activates automatically** using `_FALLBACK_VULNERABLE_PYPI` and `_FALLBACK_VULNERABLE_NPM` when OSV.dev is unreachable

## Frequently Asked Questions

### What happens when OSV.dev is unreachable during a scan?

If the OSV.dev API returns a network error or timeout, SkillSpector sets `_last_query_ok = False` and automatically falls back to built-in static vulnerability lists (`_FALLBACK_VULNERABLE_PYPI` for Python, `_FALLBACK_VULNERABLE_NPM` for Node.js). The system emits a warning finding to notify users that the results are based on offline data rather than live OSV.dev vulnerability lookups.

### How does SkillSpector prevent redundant API calls for the same dependencies?

The [`osv_client.py`](https://github.com/NVIDIA/SkillSpector/blob/main/osv_client.py) module implements an in-memory `_cache` dictionary keyed by `(name, version, ecosystem)` tuples with a one-hour TTL. Subsequent scans within the TTL window return cached `VulnResult` objects, eliminating redundant HTTP requests to OSV.dev.

### What is the batch size limit for vulnerability detail retrieval?

SkillSpector caps detail retrieval at 10 vulnerability IDs per batch when calling `_fetch_vuln_details`. This prevents hitting OSV.dev rate limits while still gathering complete severity information and advisory summaries for each identified vulnerability.

### Which ecosystems does SkillSpector support for OSV.dev queries?

As implemented in the source code, SkillSpector supports **PyPI** (Python) using `ECOSYSTEM_PYPI` and **npm** (Node.js) using `ECOSYSTEM_NPM`. The ecosystem constant determines which package registry OSV.dev searches when processing the batch query.