How to Interpret SkillSpector Risk Scores and Severity Levels on the 0-100 Scale
SkillSpector calculates risk scores from 0 to 100 by assigning fixed weights to findings (CRITICAL=50, HIGH=25, MEDIUM=10, LOW=5), applies a 1.3x multiplier if executable scripts are detected, then maps the result to severity bands where scores 81+ indicate CRITICAL risk and 0-20 indicate LOW risk.
NVIDIA/SkillSpector is an open-source security analysis framework that evaluates skill bundles and quantifies risk using a standardized 0-100 scale. Understanding how to interpret these risk scores and severity levels is essential for making informed deployment decisions. This guide breaks down the scoring algorithm, severity thresholds, and recommendation logic as implemented in the source code.
How SkillSpector Calculates Risk Scores
The scoring logic resides in src/skillspector/nodes/report.py within the _compute_risk_score function. The calculation follows a deterministic two-phase process: base accumulation from findings and conditional multipliers.
Base Scoring Weights
Each security finding contributes a fixed point value based on its severity classification:
- CRITICAL: +50 points
- HIGH: +25 points
- MEDIUM: +10 points
- LOW: +5 points
These weights are hardcoded in the _compute_risk_score function (lines 78-92). The engine iterates through all findings in the skill bundle and accumulates the sum based on each finding's severity level as defined in src/skillspector/models.py.
Executable Script Multiplier
If the bundle contains any executable scripts, SkillSpector applies a 1.3x multiplier to the total score. This boost reflects the increased attack surface posed by executable code. The final score is capped at 100 to maintain the bounds of the scale, as implemented in lines 92-94 of report.py.
Severity Bands and Recommendations
After calculating the numeric score, SkillSpector maps it to a severity band using thresholds defined in _RISK_SEVERITY_BANDS (lines 54-56). The mapping logic iterates through thresholds in descending order until finding the appropriate match (lines 96-101).
| Score ≥ | Severity | Recommendation |
|---|---|---|
| 81 | CRITICAL | DO_NOT_INSTALL |
| 51 | HIGH | DO_NOT_INSTALL |
| 21 | MEDIUM | CAUTION |
| 0 | LOW | SAFE |
The recommendation strings are defined in _RISK_RECOMMENDATION (lines 56-60). A score of 50 falls into MEDIUM severity with a CAUTION recommendation, while 51 shifts to HIGH severity with a DO_NOT_INSTALL recommendation.
Accessing Risk Data Programmatically
The risk assessment data is stored in the graph state (src/skillspector/state.py, lines 66-71) as risk_score, risk_severity, and risk_recommendation. When using the JSON output format, these values appear under the risk_assessment key.
import subprocess
import json
import pathlib
skill_path = pathlib.Path("/path/to/skill")
result = subprocess.run(
["skillspector", str(skill_path), "--output-format", "json"],
capture_output=True,
text=True,
check=True
)
report = json.loads(result.stdout)
risk = report["risk_assessment"]
print(f"Risk score: {risk['score']}/100")
print(f"Severity: {risk['severity']}")
print(f"Action: {risk['recommendation']}")
Typical output:
Risk score: 55/100
Severity: HIGH
Action: DO_NOT_INSTALL
Implementation Details
The severity scoring depends on the Finding model defined in src/skillspector/models.py, which provides the severity field that drives the point accumulation. Unit tests in tests/nodes/test_report.py verify the scoring arithmetic and band mapping logic, ensuring edge cases like threshold boundaries (e.g., exactly 50 vs. 51 points) are handled correctly according to the _RISK_SEVERITY_BANDS definitions.
Summary
- SkillSpector risk scores range from 0 (lowest risk) to 100 (highest risk).
- Base scoring assigns CRITICAL findings 50 points, HIGH 25 points, MEDIUM 10 points, and LOW 5 points.
- Executable scripts trigger a 1.3x multiplier capped at 100.
- Severity bands use thresholds at 21, 51, and 81 to delineate LOW, MEDIUM, HIGH, and CRITICAL risks.
- Recommendations map LOW to SAFE, MEDIUM to CAUTION, and HIGH/CRITICAL to DO_NOT_INSTALL.
- Access risk data via the
risk_assessmentobject in JSON output or the state fields insrc/skillspector/state.py.
Frequently Asked Questions
What is the maximum possible SkillSpector risk score?
The maximum score is 100. Even if the weighted sum of findings exceeds 100 or the 1.3x executable script multiplier pushes the total higher, the _compute_risk_score function in src/skillspector/nodes/report.py caps the final value at 100.
How does SkillSpector distinguish between HIGH and MEDIUM risk?
The threshold is set at 51 points. A score of 50 or below maps to MEDIUM severity with a CAUTION recommendation, while 51 or above maps to HIGH severity with a DO_NOT_INSTALL recommendation. This boundary is defined in _RISK_SEVERITY_BANDS in the report node.
Why does SkillSpector multiply scores by 1.3 for executable scripts?
Executable scripts pose elevated security risks because they can run arbitrary code on the target system. The 1.3x multiplier reflects this increased attack surface and potential for malicious behavior, ensuring that bundles containing executables receive appropriately higher risk ratings before the final cap is applied.
Where can I find the risk assessment data in the output?
Risk data is stored in three locations: the internal graph state (risk_score, risk_severity, risk_recommendation in src/skillspector/state.py), the JSON output under the risk_assessment key, and in formatted text or markdown reports. All formats consume the same underlying values computed by _compute_risk_score.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →