How OSV.dev Vulnerability Lookup Works in SkillSpector: Live API with Offline Fallback Support

SkillSpector's supply-chain analyzer (SC4) performs a live OSV.dev vulnerability lookup for project dependencies, then automatically falls back to a curated static vulnerability database when the API is unreachable or returns incomplete coverage.

The NVIDIA SkillSpector repository implements a robust two-stage vulnerability detection system in its supply-chain security analyzer. This architecture ensures that Python and JavaScript dependencies are checked against the latest OSV.dev advisory database while maintaining reliable offline detection through embedded fallback data. The implementation spans osv_client.py for API communication and static_patterns_supply_chain.py for orchestration and offline coverage.

How OSV.dev Vulnerability Lookup Works

The live vulnerability assessment operates through batched API queries with intelligent caching and strict timeout handling.

Live OSV.dev API Query

For each dependency discovered in requirements.txt or package.json files, SkillSpector constructs a query batch and invokes query_batch() from osv_client.py. The client generates a cache key using _cache_key() based on the package name, version, and ecosystem (ECOSYSTEM_PYPI for PyPI or ECOSYSTEM_NPM for npm).

If the package is not cached, the client sends an HTTP POST request to https://api.osv.dev/v1/querybatch with a 10-second timeout. Upon receiving the response, query_batch() extracts vulnerability IDs and retrieves detailed information for up to ten IDs using _fetch_vuln_details(). Each entry is parsed into a VulnResult object and stored in the in-memory cache via _put_cache().

In-Memory Caching Strategy

The OSV client implements a time-bound cache to avoid redundant API calls during analysis runs. The _cache dictionary stores tuples of (timestamp, results) per package, with a TTL (time-to-live) of one hour defined by _CACHE_TTL_SECS. When query_batch() processes a package, it first attempts _get_cached() using the computed cache key; if valid cached data exists, the function returns immediately without network overhead.

Graceful Error Handling

If the network request fails due to HTTP errors, timeouts, or malformed JSON responses, query_batch() returns an empty list for all packages in the batch. This signals to the orchestration layer in static_patterns_supply_chain.py that the live lookup is unavailable, triggering immediate activation of the offline fallback mechanism.

Offline Fallback for Supply Chain Security

When OSV.dev lookups fail or leave certain packages without coverage, SkillSpector seamlessly transitions to a static vulnerability database embedded in the source code.

Static Vulnerability Database

The fallback data resides in static_patterns_supply_chain.py as two constant tables: _FALLBACK_VULNERABLE_PYPI and _FALLBACK_VULNERABLE_NPM. Each entry follows the tuple structure (package_name, max_safe_version, description, confidence), containing known vulnerable versions curated by the SkillSpector maintainers.

Coverage Gap Analysis

After the live lookup completes, the _sc4_from_osv() function returns both the vulnerability findings and a set of covered package names (osv_covered). The analyzer then computes coverage gaps:

uncovered_packages = [
    p for p in packages 
    if p[0].lower().replace("_", "-") not in osv_covered
]

The _sc4_from_fallback() function receives this list of uncovered packages and matches them against the static tables, ensuring no dependency escapes analysis due to API limitations.

Severity and Version Matching

Fallback findings are automatically assigned Severity.HIGH regardless of the original vulnerability severity. When a static entry specifies a max_safe version, the code compares it against the detected version using _version_lt(). If the installed version is lower (and therefore vulnerable), the finding includes a remediation suggestion formatted as >={max_safe}.

Implementation Details and Code Examples

The following examples demonstrate how to interact with SkillSpector's vulnerability detection components directly.

Querying the OSV Client Directly

To check specific packages without running the full analysis pipeline:

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

# Look up two packages simultaneously

pkgs = [("requests", "2.28.0"), ("pyyaml", None)]
results = query_batch(pkgs, ECOSYSTEM_PYPI)

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

Running the Full SC4 Analysis

Execute the complete supply-chain analyzer including both live and fallback stages:

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

# Minimal state mimicking SkillSpector's runtime

state = SkillspectorState(
    components=["requirements.txt"],
    file_cache={"requirements.txt": open("requirements.txt").read()},
    manifest={},
)

response = node(state)
for finding in response["findings"]:
    if finding.rule_id == "SC4":
        print(finding.message)

Detecting Offline Mode

Check API availability before triggering analysis:

from skillspector.nodes.analyzers.osv_client import is_available

if not is_available():
    print("OSV.dev is unreachable – static fallback will be used automatically.")

Key Design Benefits

SkillSpector's dual-layer approach provides several architectural advantages:

  • Hybrid coverage combines the freshness of live OSV.dev data with the reliability of static vulnerability tables
  • Graceful degradation ensures security scanning continues uninterrupted during network outages
  • Performance optimization through 1-hour TTL caching reduces redundant API calls for repeated package versions
  • Ecosystem flexibility supports both PyPI and npm dependencies through unified ECOSYSTEM constants
  • Severity consistency maps OSV severity levels via _osv_severity_to_app() while maintaining high-severity defaults for offline findings

Summary

  • SkillSpector checks dependencies via query_batch() in osv_client.py, which queries https://api.osv.dev/v1/querybatch with 10-second timeouts
  • In-memory caching stores results for one hour (_CACHE_TTL_SECS) to optimize repeated lookups
  • Network failures trigger automatic fallback to _FALLBACK_VULNERABLE_PYPI and _FALLBACK_VULNERABLE_NPM in static_patterns_supply_chain.py
  • Uncovered packages are identified by comparing against osv_covered and processed by _sc4_from_fallback()
  • Fallback findings always use Severity.HIGH and include safe version recommendations when max_safe_version is defined

Frequently Asked Questions

What happens when the OSV.dev API is unreachable?

When the API returns HTTP errors, times out after 10 seconds, or returns malformed JSON, query_batch() returns an empty list and logs a warning via logger.warning. The SC4 analyzer in static_patterns_supply_chain.py detects this condition and immediately processes all discovered dependencies through the offline fallback tables, ensuring continuous vulnerability detection without manual intervention.

How does SkillSpector handle cached vulnerability data?

The OSV client maintains an in-memory cache (_cache) that stores query results with timestamps. Before making network requests, _get_cached() checks if valid data exists using a cache key derived from package name, version, and ecosystem. Cached entries expire after one hour (_CACHE_TTL_SECS), after which _put_cache() updates the storage with fresh API results.

Which package ecosystems does the OSV.dev lookup support?

SkillSpector currently supports PyPI and npm ecosystems through the constants ECOSYSTEM_PYPI = "PyPI" and ECOSYSTEM_NPM = "npm" defined in osv_client.py. The analyzer automatically detects the appropriate ecosystem based on file type—requirements.txt triggers PyPI analysis while package.json triggers npm analysis via _extract_packages_from_requirements() and _extract_packages_from_package_json() respectively.

How are severity levels determined for fallback findings?

All fallback vulnerabilities are assigned Severity.HIGH regardless of their actual CVSS score or severity in the OSV database. This conservative approach ensures that offline findings receive immediate attention. In contrast, live OSV results are normalized through _osv_severity_to_app() to map OSV severity strings to SkillSpector's internal severity enumeration.

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 →