How SkillSpector Handles Offline and Air-Gapped Vulnerability Scanning

SkillSpector automatically falls back to a built-in static database of high-severity vulnerabilities when the OSV.dev API is unreachable, ensuring continuous security scanning in air-gapped environments without manual configuration.

NVIDIA's SkillSpector is designed to operate reliably across diverse network conditions, including isolated corporate networks and CI/CD pipelines with no external connectivity. The tool's SC4 rule (known vulnerable dependencies) implements a two-stage detection architecture that prioritizes live intelligence but gracefully degrades to static signatures when air-gapped.

Two-Stage Vulnerability Detection Architecture

The SC4 analyzer operates through a dual-path system defined in src/skillspector/nodes/analyzers/static_patterns_supply_chain.py. First, it attempts a live lookup against the public OSV.dev API for the most current vulnerability data. If the network request fails or returns empty, the scanner immediately switches to an offline fallback using embedded static lists of critical vulnerabilities.

This architecture ensures that SkillSpector offline vulnerability scanning requires zero configuration changes—users run the same commands whether online or air-gapped, and the tool adapts automatically based on network availability.

Live OSV.dev Lookup (Online Path)

When internet connectivity is available, SkillSpector extracts dependency manifests from requirements.txt, pyproject.toml, setup.py, Pipfile (Python), or package.json (Node.js). It then calls the query_batch(pkg_pairs, ecosystem) function in osv_client.py, which issues a single POST request to https://api.osv.dev/v1/querybatch.

The OSV.dev results are transformed into AnalyzerFinding objects with the rule_id="SC4" and severity derived from the most severe CVE returned. Results are cached in-memory for one hour via _osv_cache to minimize repeated network traffic across multiple scans.

Static Fallback Database (Offline Mode)

If the HTTP request fails or the API returns no data, SkillSpector activates its offline capabilities through the _sc4_from_fallback function.

The Fallback Data Structure

The static database is stored in two module-level constants:

  • _FALLBACK_VULNERABLE_PYPI for Python packages
  • _FALLBACK_VULNERABLE_NPM for Node.js packages

These lists contain a curated set of high-impact CVEs with safe version boundaries, ensuring the scanner recognizes critical vulnerabilities even without API access.

Implementation in _sc4_from_fallback

The function iterates over dependencies not covered by the OSV results and checks them against the static database. According to the source code (lines 643-674), when a match is found, it generates a finding with Severity.HIGH:

def _sc4_from_fallback(...):
    """Emit SC4 findings from the static fallback list (offline mode)."""
    if max_safe is None:
        findings.append(
            AnalyzerFinding(
                rule_id="SC4",
                message=f"Known Vulnerable Dependency: {pkg_name} ({cve_info})",
                severity=Severity.HIGH,
                # ...

            )
        )
    elif pkg_version and _version_lt(pkg_version, max_safe):
        findings.append(
            AnalyzerFinding(
                rule_id="SC4",
                message=(
                    f"Known Vulnerable Dependency: {pkg_name}=={pkg_version}"
                    f" (fix: >={max_safe}, {cve_info})"
                ),
                severity=Severity.HIGH,
                # ...

            )
        )

Integration and Execution Flow

The orchestration logic in _analyze_dependencies (lines 84-112) coordinates both detection methods. It first executes _sc4_from_osv for the live lookup, then identifies uncovered packages and supplements findings with _sc4_from_fallback:

osv_findings, osv_covered = _sc4_from_osv(...)
findings.extend(osv_findings)

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

This integration point ensures that air-gapped environments receive complete coverage, with the static database acting as a safety net for any packages the OSV lookup could not assess.

Caching and Robustness

The _osv_cache dictionary provides one-hour in-memory caching of OSV.dev results, reducing network overhead for repeated scans. When running in air-gapped mode, this cache simply remains unpopulated, and the system relies entirely on the static fallback lists.

The fallback database is intentionally lightweight—containing only high-severity vulnerabilities—to balance offline utility with bundle size. This guarantees that the scanner produces meaningful SC4 findings even when no outbound HTTPS is possible.

Running SkillSpector in Air-Gapped Environments

Standard Scan (Automatic Fallback)

Execute the same command regardless of network status:

skillspector scan ./my-skill/

If the OSV.dev API is unreachable, the CLI automatically emits findings from the static fallback database without user intervention.

Simulating Offline Conditions

To test air-gapped behavior, block outbound network traffic before scanning:


# Example using network isolation

unshare -n skillspector scan ./my-skill/

The output will display SC4 findings sourced from the built-in static database rather than live CVE data.

Python API for Custom Pipelines

For programmatic control in isolated environments, invoke the analyzer directly:

from skillspector import graph

result = graph.invoke({
    "input_path": "./my-skill/",
    "output_format": "json",
    "use_llm": False,  # Static-only analysis

})

for f in result["filtered_findings"]:
    if f["rule_id"] == "SC4":
        print(f"[{f['severity']}] {f['message']}")

Summary

  • Automatic degradation: SkillSpector transitions from live OSV.dev queries to static fallback lists without configuration changes when network access is unavailable.
  • High-severity coverage: The offline database (_FALLBACK_VULNERABLE_PYPI and _FALLBACK_VULNERABLE_NPM) focuses on critical vulnerabilities, assigning Severity.HIGH to all matches.
  • Unified workflow: The _analyze_dependencies function in static_patterns_supply_chain.py seamlessly merges OSV results with fallback findings to ensure complete coverage.
  • Performance optimized: One-hour in-memory caching (_osv_cache) reduces redundant network calls in connected environments while having zero impact on air-gapped operations.

Frequently Asked Questions

Does SkillSpector require internet access to detect vulnerabilities?

No. While SkillSpector prefers the OSV.dev API for real-time vulnerability data, it includes a built-in static database of high-severity vulnerabilities that activates automatically when the API is unreachable. This ensures that air-gapped environments and offline CI runners still receive critical security findings.

What vulnerability database does SkillSpector use for offline scanning?

SkillSpector uses embedded static lists named _FALLBACK_VULNERABLE_PYPI and _FALLBACK_VULNERABLE_NPM located in src/skillspector/nodes/analyzers/static_patterns_supply_chain.py. These contain curated high-impact CVEs for Python and Node.js packages, allowing the SC4 rule to function without external API calls.

How does SkillSpector decide when to use offline mode?

The decision occurs automatically in the _sc4_from_osv function. If the HTTP request to https://api.osv.dev/v1/querybatch fails or returns no data, the _analyze_dependencies function routes uncovered packages to _sc4_from_fallback. This offline path requires no manual flags or configuration changes.

Can I manually force offline mode in SkillSpector?

There is no explicit --offline flag in the current implementation. To force offline scanning, you must block network access at the system level (e.g., using iptables, network namespaces, or running in a container without internet connectivity). When the OSV.dev request fails, the scanner automatically uses the static fallback database.

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 →