# How SkillSpector Handles Offline and Air-Gapped Vulnerability Scanning

> SkillSpector ensures continuous vulnerability scanning in air-gapped environments by automatically falling back to a built-in database when the OSV.dev API is unreachable.

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

---

**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`](https://github.com/NVIDIA/SkillSpector/blob/main/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`](https://github.com/NVIDIA/SkillSpector/blob/main/requirements.txt), [`pyproject.toml`](https://github.com/NVIDIA/SkillSpector/blob/main/pyproject.toml), [`setup.py`](https://github.com/NVIDIA/SkillSpector/blob/main/setup.py), `Pipfile` (Python), or [`package.json`](https://github.com/NVIDIA/SkillSpector/blob/main/package.json) (Node.js). It then calls the `query_batch(pkg_pairs, ecosystem)` function in [`osv_client.py`](https://github.com/NVIDIA/SkillSpector/blob/main/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**:

```python
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`:

```python
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:

```bash
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:

```bash

# 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:

```python
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`](https://github.com/NVIDIA/SkillSpector/blob/main/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`](https://github.com/NVIDIA/SkillSpector/blob/main/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.