Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3051348
fix: recognize current ngrok tunnel domains and add bore.pub/serveo.n…
federicoroncallo-hub Jul 2, 2026
0b01f29
feat(static): flag unpinned dependencies in scanned skill packages
federicoroncallo-hub Jul 2, 2026
7b24c8a
feat(static): classify URLs in config files via shared url_classifier
federicoroncallo-hub Jul 2, 2026
4ebaaf1
refactor(static): scan config files via raw URL extraction
federicoroncallo-hub Jul 2, 2026
d7d4790
feat(static): scan more manifest formats for unpinned dependencies
federicoroncallo-hub Jul 2, 2026
fa5b246
feat: add OSV dependency vulnerability analyzer (--use-osv)
federicoroncallo-hub Jul 2, 2026
1d0449b
feat(osv): collect pinned dependencies from more manifest formats
federicoroncallo-hub Jul 2, 2026
e70193f
fix(llm): allow Vertex AI to use ambient Application Default Credentials
gyrospectre Jul 24, 2026
cbf9fce
Bumps to resolve security findings
gyrospectre Jul 25, 2026
adfbc89
fix(llm): don't leak Vertex ADC credential path into GEMINI_API_KEY
gyrospectre Aug 3, 2026
48ba248
revert unrelated cli-command-reference.md regeneration
gyrospectre Aug 3, 2026
ecc0720
fix(static): classify suspicious URLs by hostname
vineethsai7 Aug 3, 2026
93ba6f0
fix(static): tolerate malformed setup.py input
vineethsai7 Aug 3, 2026
6994a42
fix(static): harden URL classification and reporting
vineethsai7 Aug 3, 2026
17eb230
Merge commit '93ba6f0b' into HEAD
vineethsai7 Aug 3, 2026
6ececb1
docs(static): correct analyzer pass count
vineethsai7 Aug 3, 2026
a419477
Merge remote-tracking branch 'origin/main' into HEAD
vineethsai7 Aug 3, 2026
4c5c18c
Merge commit 'a4194779' into HEAD
vineethsai7 Aug 3, 2026
8b50b49
Merge commit 'a4194779' into HEAD
vineethsai7 Aug 3, 2026
68285f4
Merge commit '8b50b498' into HEAD
vineethsai7 Aug 3, 2026
a71e8d8
Merge commit '4c5c18cc' into HEAD
vineethsai7 Aug 3, 2026
961588c
fix(static): validate suspicious URL schemes
vineethsai7 Aug 3, 2026
d4c7654
docs(vertex): clarify conditional ADC configuration
vineethsai7 Aug 3, 2026
c1d47d9
Merge commit 'd4c76544' into HEAD
vineethsai7 Aug 3, 2026
6973751
Merge commit '961588c1' into HEAD
vineethsai7 Aug 3, 2026
62c10be
Merge commit '6973751c' into HEAD
vineethsai7 Aug 3, 2026
a387d2c
Merge commit '62c10be4' into HEAD
vineethsai7 Aug 3, 2026
ea9eb7e
Merge main into feat/pr2-unpinned-deps
vineethsai7 Aug 3, 2026
8c00123
Merge commit 'ea9eb7e33fb9a4d39ae2d01b016b97c45dc5b9cb' into HEAD
vineethsai7 Aug 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/architecture/analyzers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Analyzers implement independent detection strategies and return normalized `Find
| Behavioral | Static AST/dataflow | No | 1 | Python source behavior |
| VirusTotal | External intel | Yes | 1 | Binary hash/file reputation |
| AI Defense | External service | Yes | 1 | Prompt/content/code threat signal |
| OSV | External service | No | 1 | Known-vulnerable pinned dependencies |
| Trigger | Heuristic | No | 1 | Vague or risky trigger descriptions |
| LLM | Semantic | Usually (not required for Bedrock IAM mode) | 2 | Intent-level threat reasoning |
| Meta | Semantic post-pass | Usually (not required for Bedrock IAM mode) | 2 | FP filtering and prioritization |
Expand Down Expand Up @@ -44,5 +45,6 @@ See [Scanning Pipeline](../scanning-pipeline.md) for the full execution flow.
- [LLM Analyzer](llm-analyzer.md)
- [Meta-Analyzer](meta-analyzer.md)
- [AI Defense Analyzer](aidefense-analyzer.md)
- [OSV Analyzer](osv-analyzer.md)
- [Analyzer Selection Guide](meta-and-external-analyzers.md)
- [Writing Custom Rules](writing-custom-rules.md)
17 changes: 16 additions & 1 deletion docs/architecture/analyzers/meta-and-external-analyzers.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This page helps you choose which optional analyzers to enable for your use case.
| Cloud-based threat classification | AI Defense | `--use-aidefense` | Requires Cisco AI Defense API access |
| Catch vague/risky skill descriptions | Trigger | `--use-trigger` | Lightweight; no external dependencies |
| Python dataflow and cross-file analysis | Behavioral | `--use-behavioral` | CPU-intensive for large codebases |
| Known-vulnerable dependency detection | OSV | `--use-osv` | Requires network; queries PyPI pins only (no API key) |

## When to Use Each Analyzer

Expand Down Expand Up @@ -99,15 +100,28 @@ Skip when: the skill contains no Python source, or you need the fastest possible

See [Behavioral Analyzer deep dive](behavioral-analyzer.md) for detection patterns.

### OSV Analyzer

Best for: skills that declare pinned Python dependencies you want checked against known CVEs/advisories. Queries the free, open [OSV.dev](https://osv.dev) database — no API key required.

```bash
skill-scanner scan ./my-skill --use-osv
```

Skip when: scanning air-gapped/offline (it requires network access), or the skill declares no exactly pinned dependencies. It fails open — a network error logs a warning and yields no findings.

See [OSV Analyzer deep dive](osv-analyzer.md) for details.

## Recommended Combinations

| Scenario | Flags |
|---|---|
| Quick CI gate | (defaults -- core analyzers only) |
| Thorough single-skill review | `--use-llm --use-behavioral --use-trigger --enable-meta` |
| Binary-heavy skill | `--use-virustotal` |
| Dependency-heavy skill | `--use-osv` |
| Enterprise with AI Defense | `--use-aidefense --use-llm --enable-meta` |
| Maximum coverage | `--use-llm --use-behavioral --use-trigger --use-virustotal --enable-meta` |
| Maximum coverage | `--use-llm --use-behavioral --use-trigger --use-virustotal --use-osv --enable-meta` |

## Bytecode Analyzer

Expand All @@ -128,4 +142,5 @@ skill-scanner scan-all ./skills-dir --check-overlap
- [LLM Analyzer](llm-analyzer.md)
- [Meta Analyzer](meta-analyzer.md)
- [AI Defense Analyzer](aidefense-analyzer.md)
- [OSV Analyzer](osv-analyzer.md)
- [Binary Handling](../binary-handling.md)
86 changes: 86 additions & 0 deletions docs/architecture/analyzers/osv-analyzer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# OSV Analyzer

## Overview

The OSV Analyzer checks a skill's declared Python dependencies against the
[OSV.dev](https://osv.dev) vulnerability database — a free, open aggregator of
security advisories (GHSA, PYSEC, CVE, and more). It is an **opt-in external
analyzer** (like VirusTotal): it requires network access, needs **no API key**,
and **fails open** so a network problem never breaks a scan.

## What It Detects

- **Known-vulnerable dependency versions** — a pinned dependency
(`package==1.2.3`) that has one or more advisories in OSV is flagged as
`SUPPLY_CHAIN_KNOWN_VULNERABILITY` (HIGH), with the advisory IDs and links.

Only dependencies pinned to an **exact** version are queried. An open range
(`package>=1`) has no single version to look up; that risk is already surfaced
by the static [unpinned-dependency check](static-analyzer.md).

## Sources Scanned

| Source | Notes |
|--------|-------|
| `requirements*.txt` | `requirements.txt`, `requirements-dev.txt`, etc. |
| `pyproject.toml` | `[project]` dependencies and optional-dependencies (PEP 621) |
| `setup.cfg` | `[options] install_requires` and `[options.extras_require]` |
| `setup.py` | String literals inside `install_requires=[...]` (parsed via AST, not executed) |
| `Pipfile` | `[packages]` and `[dev-packages]` sections |
| Manifest `metadata.dependencies` | Optional list of requirement strings in SKILL.md frontmatter |

Ecosystem defaults to `PyPI`.

## Usage

### Command Line

```bash
# Enable OSV dependency scanning (no API key needed)
skill-scanner scan /path/to/skill --use-osv

# Combine with other analyzers
skill-scanner scan /path/to/skill --use-osv --use-behavioral
```

### Python API

```python
from skill_scanner.core.analyzers.osv_analyzer import OSVAnalyzer
from skill_scanner.core.loader import SkillLoader

analyzer = OSVAnalyzer(enabled=True)
skill = SkillLoader().load_skill("/path/to/skill")
findings = analyzer.analyze(skill)
```

### API

Set `use_osv: true` on the scan request (see the
[API Endpoint Reference](../../reference/api-endpoint-reference.md)).

## How It Works

1. **Collect pins** — parse every supported dependency source (see
[Sources Scanned](#sources-scanned)), keeping only exact `==` pins as
`(name, version)` pairs.
2. **Batch query** — POST all pins to `https://api.osv.dev/v1/querybatch`
(`{"package": {"ecosystem": "PyPI", "name": ...}, "version": ...}`).
3. **Generate findings** — for each package that returns advisories, emit a
`SUPPLY_CHAIN_KNOWN_VULNERABILITY` finding listing the advisory IDs.

## Error Handling

The analyzer fails open. On any network/HTTP error it logs a warning and
returns no findings, so an offline or air-gapped environment simply skips the
check rather than failing the scan.

## Dependencies

Uses `httpx`, which is already a scanner dependency — enabling OSV adds **no new
runtime dependency** and no API key.

## Related Pages

- [Analyzer Selection Guide](meta-and-external-analyzers.md) — when to enable `--use-osv`
- [Static Analyzer](static-analyzer.md) — the complementary unpinned-dependency check
7 changes: 5 additions & 2 deletions docs/architecture/analyzers/static-analyzer.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> [!TIP]
> **TL;DR**
>
> The static analyzer runs 14 detection passes per skill covering YAML signatures, YARA rules, Python checks, binary inspection, document analysis, homoglyph detection, and allowed-tools enforcement. It is always-on (core analyzer) and requires no external services.
> The static analyzer runs 15 detection passes per skill covering YAML signatures, YARA rules, Python checks, binary inspection, document analysis, homoglyph detection, dependency pinning, and allowed-tools enforcement. It is always-on (core analyzer) and requires no external services.

The static analyzer is the primary deterministic detection engine. It combines YAML signature matching, YARA-X rule scanning, Python-based checks, and file inventory analysis to detect security threats without requiring external services.

Expand All @@ -18,7 +18,8 @@ flowchart TD
A["Manifest validation"] --> B["Instruction body scanning"]
B --> C["Script/code scanning"]
C --> D["Consistency checks"]
D --> D3["Config file URL scanning"]
D --> D2["Dependency pinning checks"]
D2 --> D3["Config file URL scanning"]
D3 --> E["Referenced file scanning"]
E --> F["Binary file checks"]
F --> G["Hidden file checks"]
Expand All @@ -42,6 +43,7 @@ Each pass targets a different aspect of the skill package:
| Instruction body | `_scan_instruction_body()` | SKILL.md content against signature rules |
| Script scanning | `_scan_scripts()` | Python/bash/other scripts against signatures |
| Consistency | `_check_consistency()` | Mismatch between manifest claims and actual behavior |
| Dependency pinning | `_check_dependency_pinning()` | Unpinned dependencies in `requirements*.txt`, `pyproject.toml`, `setup.cfg`, `setup.py`, `Pipfile`, and manifest metadata |
| Config file URLs | `_scan_config_files()` | URLs in config/settings/TOML files classified via the shared `url_classifier` |
| Referenced files | `_scan_referenced_files()` | Files mentioned in SKILL.md instructions |
| Binary files | `_check_binary_files()` | Extension/magic mismatch, archive detection, unknown binaries |
Expand Down Expand Up @@ -99,6 +101,7 @@ The pack manifest registers all rule sources and metadata for the core detection
- Hardcoded credentials and secrets
- Archive/binary risks
- Tool mismatch and manifest consistency
- Supply-chain risk from unpinned dependencies
- Suspicious/tunnel URLs in configuration files
- Hidden file and dotfile risks
- Document-embedded threats (PDF, Office macros)
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/threat-taxonomy.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Skill Scanner currently uses a subset of those codes for agent-skill risk catego
| Code Execution | `AITech-9.1` | `AISubtech-9.1.1` | Unsafe execution primitives |
| Obfuscation | `AITech-9.2` | `AISubtech-9.2.1` | Detection-evasion obfuscation patterns |
| ASCII Smuggling | `AITech-9.2` | `AISubtech-9.2.1` | Unicode Tag Block (U+E0000–U+E007F) used to hide prompt-injection payloads inside skill files; invisible in editors but decoded by LLMs |
| Supply Chain Attack | `AITech-9.3` | `AISubtech-9.3.1` | Malicious package/tool injection |
| Supply Chain Attack | `AITech-9.3` | `AISubtech-9.3.1` | Malicious package/tool injection; unpinned dependency versions |
| Unauthorized Tool Use | `AITech-12.1` | `AISubtech-12.1.3` | Unsafe/undeclared tool execution |
| Tool Poisoning | `AITech-12.1` | `AISubtech-12.1.2` | Tampering with tool behavior/data |
| Tool Shadowing | `AITech-12.1` | `AISubtech-12.1.4` | Malicious lookalike/replacement tools |
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/api-endpoint-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ curl -X POST http://localhost:8000/scan-upload \
| `use_aidefense` | `bool` |
| `aidefense_api_url` | `str | None` |
| `use_trigger` | `bool` |
| `use_osv` | `bool` |
| `enable_meta` | `bool` |
| `llm_consensus_runs` | `int` |

Expand Down Expand Up @@ -131,6 +132,7 @@ curl -X POST http://localhost:8000/scan-upload \
| `use_aidefense` | `bool` |
| `aidefense_api_url` | `str | None` |
| `use_trigger` | `bool` |
| `use_osv` | `bool` |
| `enable_meta` | `bool` |
| `llm_consensus_runs` | `int` |

Expand Down
7 changes: 7 additions & 0 deletions docs/reference/cli-command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Flags shared by `scan` and `scan-all`:
| `--use-behavioral` | off | Enable the behavioral analyzer |
| `--use-virustotal` | off | Enable VirusTotal hash lookups |
| `--use-aidefense` | off | Enable Cisco AI Defense analyzer |
| `--use-osv` | off | Enable OSV.dev dependency vulnerability scanning (no API key; requires network) |
| `--enable-meta` | off | Enable the meta (cross-correlation) analyzer |
| `--fail-on-findings` | off | Exit non-zero if critical or high findings are reported; equivalent to `--fail-on-severity high` (CI gate) |
| `--fail-on-severity LEVEL` | off | Exit non-zero if findings at or above LEVEL exist (critical, high, medium, low, info) |
Expand Down Expand Up @@ -156,6 +157,8 @@ options:
--use-aidefense Enable AI Defense analyzer (requires API key)
--aidefense-api-key AIDEFENSE_API_KEY
AI Defense API key (or set AI_DEFENSE_API_KEY)
--use-osv Enable OSV.dev dependency vulnerability scanning (no
API key; requires network)
--aidefense-api-url AIDEFENSE_API_URL
AI Defense API URL (optional, defaults to US region)
--llm-provider {anthropic,openai}
Expand Down Expand Up @@ -268,6 +271,8 @@ options:
--use-aidefense Enable AI Defense analyzer (requires API key)
--aidefense-api-key AIDEFENSE_API_KEY
AI Defense API key (or set AI_DEFENSE_API_KEY)
--use-osv Enable OSV.dev dependency vulnerability scanning (no
API key; requires network)
--aidefense-api-url AIDEFENSE_API_URL
AI Defense API URL (optional, defaults to US region)
--llm-provider {anthropic,openai}
Expand Down Expand Up @@ -384,6 +389,8 @@ options:
--use-aidefense Enable AI Defense analyzer (requires API key)
--aidefense-api-key AIDEFENSE_API_KEY
AI Defense API key (or set AI_DEFENSE_API_KEY)
--use-osv Enable OSV.dev dependency vulnerability scanning (no
API key; requires network)
--aidefense-api-url AIDEFENSE_API_URL
AI Defense API URL (optional, defaults to US region)
--llm-provider {anthropic,openai}
Expand Down
4 changes: 4 additions & 0 deletions docs/reference/configuration-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ Enable the Cisco AI Defense cloud analyzer.
| `AI_DEFENSE_API_KEY` | Cisco AI Defense analyzer API key. | `(your AI Defense key)` |
| `AI_DEFENSE_API_URL` | Cisco AI Defense endpoint override. | `https://us.api.inspect.aidefense.security.cisco.com/api/v1` |

## OSV Dependency Scanning

The OSV analyzer queries [OSV.dev](https://osv.dev) for known-vulnerable pinned dependencies. It is an external service that requires **no API key**, only outbound network access to `api.osv.dev`. Enable it with `--use-osv` (or `use_osv` on the API). Skip it in air-gapped environments — with no network it fails open and reports nothing.

## Feature Toggles

Override default analyzer enablement via environment. Values: `true`/`1` or `false`/`0`.
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/dependencies-and-llm-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ All versions from [`pyproject.toml`](https://github.com/cisco-ai-defense/skill-s
| `uvicorn[standard]` | >= 0.29.0 | ASGI server |
| `pydantic` | >= 2.6.0 | Data validation and serialization |
| `python-multipart` | >= 0.0.6 | File upload handling |
| `httpx` | >= 0.28.1 | Async HTTP client |
| `httpx` | >= 0.28.1 | HTTP client (also used by the VirusTotal, AI Defense, and OSV external analyzers) |

### CLI and TUI

Expand Down
8 changes: 8 additions & 0 deletions skill_scanner/api/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class ScanRequest(BaseModel):
use_aidefense: bool = Field(False, description="Enable AI Defense analyzer")
aidefense_api_url: str | None = Field(None, description="AI Defense API URL")
use_trigger: bool = Field(False, description="Enable trigger specificity analysis")
use_osv: bool = Field(False, description="Enable OSV.dev dependency vulnerability scanning")
enable_meta: bool = Field(False, description="Enable meta-analysis for false positive filtering")
llm_consensus_runs: int = Field(1, description="Number of LLM consensus runs (majority vote)")

Expand Down Expand Up @@ -251,6 +252,7 @@ class BatchScanRequest(BaseModel):
use_aidefense: bool = False
aidefense_api_url: str | None = None
use_trigger: bool = False
use_osv: bool = False
enable_meta: bool = Field(False, description="Enable meta-analysis")
llm_consensus_runs: int = Field(1, description="Number of LLM consensus runs (majority vote)")

Expand Down Expand Up @@ -297,6 +299,7 @@ def _build_analyzers(
aidefense_api_key: str | None = None,
aidefense_api_url: str | None = None,
use_trigger: bool = False,
use_osv: bool = False,
llm_consensus_runs: int = 1,
):
"""Build the analyzer list — delegates to the centralized factory."""
Expand All @@ -313,6 +316,7 @@ def _build_analyzers(
aidefense_api_key=aidefense_api_key,
aidefense_api_url=aidefense_api_url,
use_trigger=use_trigger,
use_osv=use_osv,
llm_consensus_runs=llm_consensus_runs,
)

Expand Down Expand Up @@ -425,6 +429,7 @@ def run_scan():
aidefense_api_key=aidefense_api_key,
aidefense_api_url=request.aidefense_api_url,
use_trigger=request.use_trigger,
use_osv=request.use_osv,
llm_consensus_runs=request.llm_consensus_runs,
)
scanner = SkillScanner(analyzers=analyzers, policy=policy)
Expand Down Expand Up @@ -505,6 +510,7 @@ async def scan_uploaded_skill(
aidefense_api_key: str | None = Header(None, alias="X-AIDefense-Key"),
aidefense_api_url: str | None = Form(None, description="AI Defense API URL"),
use_trigger: bool = Form(False, description="Enable trigger specificity analysis"),
use_osv: bool = Form(False, description="Enable OSV.dev dependency vulnerability scanning"),
enable_meta: bool = Form(False, description="Enable meta-analysis for FP filtering"),
llm_consensus_runs: int = Form(1, description="Number of LLM consensus runs"),
):
Expand Down Expand Up @@ -598,6 +604,7 @@ async def scan_uploaded_skill(
use_aidefense=use_aidefense,
aidefense_api_url=aidefense_api_url,
use_trigger=use_trigger,
use_osv=use_osv,
enable_meta=enable_meta,
llm_consensus_runs=llm_consensus_runs,
)
Expand Down Expand Up @@ -684,6 +691,7 @@ def run_batch_scan(
aidefense_api_key=aidefense_api_key,
aidefense_api_url=request.aidefense_api_url,
use_trigger=request.use_trigger,
use_osv=request.use_osv,
llm_consensus_runs=request.llm_consensus_runs,
)

Expand Down
8 changes: 8 additions & 0 deletions skill_scanner/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def _build_analyzers(policy: ScanPolicy, args: argparse.Namespace, status: Calla
aidefense_api_key=getattr(args, "aidefense_api_key", None),
aidefense_api_url=getattr(args, "aidefense_api_url", None),
use_trigger=getattr(args, "use_trigger", False),
use_osv=getattr(args, "use_osv", False),
llm_provider=getattr(args, "llm_provider", None),
llm_consensus_runs=getattr(args, "llm_consensus_runs", 1),
llm_max_tokens=getattr(args, "llm_max_tokens", None),
Expand All @@ -153,6 +154,8 @@ def _build_analyzers(policy: ScanPolicy, args: argparse.Namespace, status: Calla
status("Using AI Defense analyzer")
elif name == "trigger":
status("Using Trigger analyzer (description specificity analysis)")
elif name == "osv_analyzer":
status("Using OSV dependency vulnerability analyzer")

return analyzers

Expand Down Expand Up @@ -946,6 +949,11 @@ def _add_common_scan_flags(parser: argparse.ArgumentParser) -> None:
parser.add_argument("--use-aidefense", action="store_true", help="Enable AI Defense analyzer (requires API key)")
parser.add_argument("--aidefense-api-key", help="AI Defense API key (or set AI_DEFENSE_API_KEY)")
parser.add_argument("--aidefense-api-url", help="AI Defense API URL (optional, defaults to US region)")
parser.add_argument(
"--use-osv",
action="store_true",
help="Enable OSV.dev dependency vulnerability scanning (no API key; requires network)",
)
parser.add_argument(
"--llm-provider",
choices=["anthropic", "openai", "openai-compatible"],
Expand Down
6 changes: 6 additions & 0 deletions skill_scanner/cli/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,10 @@ def _ask_analyzers(env: dict) -> dict[str, bool]:
" Behavioral dataflow analysis",
default=False,
)
analyzers["use_osv"] = Confirm.ask(
" OSV.dev dependency vulnerability scanning [dim](requires network)[/]",
default=False,
)

console.print()
console.print("[bold]Requires API Key:[/]")
Expand Down Expand Up @@ -488,6 +492,8 @@ def _build_command(
if analyzers:
if analyzers.get("use_behavioral"):
cmd.append("--use-behavioral")
if analyzers.get("use_osv"):
cmd.append("--use-osv")
if analyzers.get("use_llm"):
cmd.append("--use-llm")
if analyzers.get("use_virustotal"):
Expand Down
9 changes: 9 additions & 0 deletions skill_scanner/core/analyzer_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def build_analyzers(
aidefense_api_key: str | None = None,
aidefense_api_url: str | None = None,
use_trigger: bool = False,
use_osv: bool = False,
llm_consensus_runs: int = 1,
llm_max_tokens: int | None = None,
) -> list[BaseAnalyzer]:
Expand Down Expand Up @@ -206,4 +207,12 @@ def build_analyzers(
except (ImportError, ValueError, TypeError) as exc:
logger.warning("Could not load Trigger analyzer: %s", exc)

if use_osv:
try:
from .analyzers.osv_analyzer import OSVAnalyzer

analyzers.append(OSVAnalyzer(enabled=True, policy=policy))
except (ImportError, ValueError, TypeError) as exc:
logger.warning("Could not load OSV analyzer: %s", exc)

return analyzers
Loading
Loading