How SkillSpector Calculates Its Security Risk Score: Methodology and Implementation

SkillSpector computes its security risk score by aggregating severity-weighted finding points, applying a 1.3× multiplier when executable scripts are detected, and mapping the result to severity bands and installation recommendations.

NVIDIA's SkillSpector analyzes skill bundles for security vulnerabilities and produces a quantitative risk assessment. The scoring methodology combines static severity weights with dynamic bundle characteristics to generate a 0–100 numeric score, a severity label, and an actionable recommendation. This calculation is performed by the private helper function _compute_risk_score in src/skillspector/nodes/report.py.

The Four-Step Risk Calculation Pipeline

The risk assessment follows a deterministic pipeline that processes security findings and bundle metadata through four distinct stages.

Step 1: Base Point Allocation by Severity

Each discovered finding contributes a fixed point value based on its severity level. The algorithm iterates through the findings list and accumulates points according to the v1 scoring rules (implemented at lines 81‑92):

Severity Points Added
CRITICAL +50
HIGH +25
MEDIUM +10
LOW +5

The subtotal represents the raw security exposure before bundle-specific modifiers.

Step 2: Executable Script Multiplier

If the scanned skill bundle contains executable scripts (indicated by has_executable_scripts == True), the base subtotal is multiplied by 1.3 to account for elevated execution risk. The result is rounded down to an integer and clamped to the valid range of 0–100 (see lines 93‑95 in src/skillspector/nodes/report.py).

This multiplier reflects the increased danger posed by findings in bundles that can execute arbitrary code.

Step 3: Severity Band Classification

The final numeric score maps to a categorical severity label using the ordered lookup list _RISK_SEVERITY_BANDS (lines 96‑100):

  • CRITICAL: Score ≥ 81
  • HIGH: Score ≥ 51
  • MEDIUM: Score ≥ 21
  • LOW: Score < 21

The function iterates through these thresholds in descending order, assigning the first matching band.

Step 4: Recommendation Mapping

Each severity band translates to a human-readable recommendation via the _RISK_RECOMMENDATION dictionary (defined at lines 55‑60 and applied at line 101):

  • LOW → SAFE
  • MEDIUM → CAUTION
  • HIGH or CRITICAL → DO_NOT_INSTALL

This final value guides users on whether to proceed with installation.

Implementation Details in report.py

The core logic resides in _compute_risk_score, which accepts two parameters: a list of Finding objects and a boolean flag for executable scripts. The function returns a tuple (score, severity_band, recommendation) that the report node injects into the final output under the "risk_assessment" section.

The calculation is stateless and deterministic—identical inputs will always produce identical scores, enabling reproducible security audits across different environments.

Code Example: Computing a Risk Score Programmatically

You can import and invoke the scoring function directly to calculate risk assessments for custom finding sets:

from skillspector.nodes.report import _compute_risk_score
from skillspector.models import Finding

# Example findings with mixed severities

findings = [
    Finding(rule_id="S001", severity="HIGH", message="Unsafe exec", file="script.py", start_line=1, end_line=5, confidence=0.9),
    Finding(rule_id="S002", severity="MEDIUM", message="Hard-coded secret", file="config.yml", start_line=10, end_line=10, confidence=0.8),
]

# Indicate the bundle contains executable scripts

has_executable_scripts = True

# Calculate the risk score

score, severity, recommendation = _compute_risk_score(findings, has_executable_scripts)

print(f"Score: {score}")                     # → 45 ( (25+10) * 1.3 = 45.5 → int(45) )

print(f"Severity: {severity}")               # → HIGH

print(f"Recommendation: {recommendation}")   # → DO_NOT_INSTALL

In this example, the base score of 35 points (25 for HIGH + 10 for MEDIUM) receives the 1.3× multiplier, resulting in 45 points which falls into the HIGH severity band.

CLI Output Format

When using the command-line interface, SkillSpector performs this calculation automatically and embeds the results in JSON or Markdown reports:


# Generate a JSON report with risk assessment

skillspector scan path/to/skill_bundle --output-format json

The output contains the computed risk data:

{
  "risk_assessment": {
    "score": 78,
    "severity": "HIGH",
    "recommendation": "DO_NOT_INSTALL"
  }
}

The CLI delegates to the same _compute_risk_score function, ensuring consistency between programmatic and command-line usage.

Key Source Files and Their Roles

File Role in Risk Score Calculation
src/skillspector/nodes/report.py Contains _compute_risk_score, severity bands, and recommendation mappings.
src/skillspector/models.py Defines the Finding model whose severity field drives point allocation.
src/skillspector/state.py Maintains has_executable_scripts and stores computed risk fields for downstream processing.
src/skillspector/cli.py Invokes the report node and surfaces risk assessments to the user interface.

Summary

  • Base scoring assigns fixed points (50/25/10/5) by severity level at lines 81‑92 of report.py.
  • Execution risk applies a 1.3× multiplier when scripts are present, clamped to 0–100 (lines 93‑95).
  • Severity classification maps scores to bands using thresholds ≥81, ≥51, ≥21, and <21 (lines 96‑100).
  • Recommendations translate severity into SAFE, CAUTION, or DO_NOT_INSTALL guidance (lines 55‑60, 101).
  • The function returns a tuple of (int_score, severity_label, recommendation_string) for downstream consumption.

Frequently Asked Questions

How does SkillSpector handle multiple findings of the same severity?

SkillSpector aggregates findings additively. Each finding contributes its severity's point value to a running total, so two HIGH severity findings contribute 50 points (25 × 2) to the base score before any multipliers are applied.

What is the maximum possible risk score in SkillSpector?

The maximum score is 100, enforced by clamping logic in _compute_risk_score. Even if the calculated points exceed 100 (for example, multiple CRITICAL findings with the executable script multiplier), the result is capped at 100 and classified as CRITICAL severity.

Why does SkillSpector multiply the score for executable scripts?

The 1.3× multiplier reflects the increased security risk of installable bundles that contain executable code. Vulnerabilities in executable scripts can lead to immediate code execution during installation or runtime, justifying the severity boost over static configuration-only bundles.

Where is the risk assessment data stored in SkillSpector's output?

The risk assessment appears under the "risk_assessment" key in JSON outputs and in the risk summary section of Markdown reports. This data structure contains three fields: score (integer), severity (string), and recommendation (string), as returned by _compute_risk_score in src/skillspector/nodes/report.py.

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 →