How Evaluation Works
Quick Answer
How does eval work with LLM, YARA, and both?
Static Analyzer Only (includes YARA):
python evals/eval_runner.py --test-skills-dir evals/skills- Uses
StaticAnalyzerwhich includes YARA rule matching - Fast, no API calls
- Tests pattern-based detection
- Uses
Static + LLM Analyzer:
export SKILL_SCANNER_LLM_API_KEY=your_key python evals/eval_runner.py --test-skills-dir evals/skills --use-llm- Uses
StaticAnalyzer+LLMAnalyzer - Combines pattern matching (YARA) with semantic analysis (LLM)
- More comprehensive but slower
- Uses
With Meta-Analyzer (false positive filtering):
python evals/eval_runner.py --test-skills-dir evals/skills --use-llm --use-meta- Adds
MetaAnalyzerfor second-pass analysis - Filters false positives, consolidates redundant findings
- Best for production-quality results
- Adds
Compare With/Without Meta-Analyzer:
python evals/eval_runner.py --test-skills-dir evals/skills --use-llm --compare- Runs evaluation twice: with and without meta-analysis
- Shows per-skill changes and overall impact
- Useful for validating meta-analyzer effectiveness
View AITech Taxonomy Codes:
python evals/eval_runner.py --test-skills-dir evals/skills --show-aitech- Displays detailed findings with AITech taxonomy codes
- Shows AITech codes (e.g.,
AITech-9.1), names, and AISubtech codes - Useful for understanding threat classification alignment with Cisco AI Security Framework
What it checks:
- Reads
_expected.jsonfrom each skill directory - Scans skill with configured analyzers
- Compares actual findings vs expected findings
- Matches by:
category+severity(exact match required)
- Reads
Current Status
With LLM Analyzer:
- Precision: 63.64% (14 TP, 8 FP)
- Recall: 63.64% (14 TP, 8 FN)
- F1 Score: 63.64%
Main Issue: Expected findings are incomplete - LLM analyzer finds more threats than documented in _expected.json files.
Detailed Explanation
Evaluation Process
1. Find all _expected.json files
↓
2. For each skill:
a. Load expected findings from _expected.json
b. Scan skill with analyzers (Static, LLM, etc.)
c. Compare actual findings vs expected findings
d. Count matches, false positives, false negatives
↓
3. Calculate aggregate metrics:
- Precision = TP / (TP + FP)
- Recall = TP / (TP + FN)
- F1 Score = harmonic mean
Matching Logic
Exact Match Required:
- Category must match exactly (e.g.,
prompt_injection) - Severity must match exactly (e.g.,
HIGH)
Example:
// Expected
{"category": "prompt_injection", "severity": "HIGH"}
// Actual Finding
category: "prompt_injection", severity: "HIGH" [OK] Match
category: "prompt_injection", severity: "CRITICAL" [NO MATCH] No match
category: "policy_violation", severity: "HIGH" [NO MATCH] No match
What Gets Counted
For Safe Skills (expected_safe: true)
- True Negative: 0 findings [OK]
- False Positive: Any finding [NO MATCH]
- Correct:
actual_safe == true && findings == 0
For Unsafe Skills (expected_safe: false)
- True Positive: Expected finding matched [OK]
- False Negative: Expected finding not found [NO MATCH]
- False Positive: Unmatched finding (only if we're missing expected findings)
- Correct:
actual_safe == false && false_negatives == 0
Key Point: Extra findings beyond expected ones are NOT false positives if all expected findings are found. Finding MORE threats is GOOD!
Why Precision/Recall Are Low
Looking at the analysis output:
Missing Expected Findings: Many skills have findings that aren't in
_expected.jsonjailbreak-override: Missing 2 category/severity combinationsmulti-file-exfiltration: Missing 4 combinationsdatabase-query: Missing 2 combinations
Expected Findings Not Found: Some expected findings aren't being detected
multi-file-exfiltration: Expectedhardcoded_secrets/HIGHbut not foundinfinite-loop: Expectedresource_abuse/MEDIUMbut foundCRITICALandHIGHinstead
Severity Mismatches: Expected severity doesn't match actual severity
- Expected
MEDIUMbut analyzer findsCRITICALorHIGH
- Expected
How to Improve Precision/Recall
Option 1: Update Expected Findings (Recommended)
Use the helper script to see what's missing:
# Set environment variables
export SKILL_SCANNER_LLM_API_KEY=your_key
export SKILL_SCANNER_LLM_MODEL=claude-3-5-sonnet-20241022
# Analyze what's missing
python evals/update_expected_findings.py --test-skills-dir evals/skills --use-llm
# Auto-update _expected.json files
python evals/update_expected_findings.py --test-skills-dir evals/skills --use-llm --update
This will:
- Scan each skill
- Compare actual findings vs expected
- Show what's missing
- Optionally update
_expected.jsonfiles
Option 2: Make Matching More Flexible
Modify eval_runner.py to match by category only (ignore severity):
# In _compare_results(), change matching logic:
if actual_finding.category.value == exp_category: # Remove severity check
matched += 1
Option 3: Update Expected Severities
If analyzer consistently finds CRITICAL but expected is HIGH, update expected to match analyzer output.
Option 4: Evaluate Analyzers Separately
Understand what each analyzer contributes:
# Test Static only
python evals/eval_runner.py --test-skills-dir evals/skills
# Test LLM only (would need code modification)
# Test Combined
python evals/eval_runner.py --test-skills-dir evals/skills --use-llm
Example: Updating Expected Findings
Before (jailbreak-override/_expected.json):
{
"expected_threats": [
{"category": "prompt_injection", "severity": "HIGH"}
]
}
After (based on actual findings):
{
"expected_findings": [
{"category": "prompt_injection", "severity": "HIGH"},
{"category": "prompt_injection", "severity": "CRITICAL"},
{"category": "policy_violation", "severity": "HIGH"}
]
}
Viewing AITech Taxonomy Codes
The eval runner can display AITech taxonomy codes (aligned with Cisco AI Security Framework) for each finding:
python evals/eval_runner.py --test-skills-dir evals/skills --show-aitech
Output Example:
Detailed Findings (with AITech Taxonomy)
============================================================
Skill: data-processor
Findings (7):
- command_injection [CRITICAL]
AITech: AITech-9.1 (Model or Agentic System Manipulation) | AISubtech: AISubtech-9.1.4 (Injection Attacks)
- data_exfiltration [HIGH]
AITech: AITech-8.2 (Data Exfiltration / Exposure)
What AITech Codes Show:
- AITech Code: Main threat category (e.g.,
AITech-9.1) - AITech Name: Human-readable category name
- AISubtech Code: Sub-category when available (e.g.,
AISubtech-9.1.4) - AISubtech Name: Human-readable sub-category name
Note: Not all findings have AITech codes. Findings from analyzers that use ThreatMapping (Static, LLM, Behavioral) will have AITech codes in their metadata. Cisco AI Defense Scanner is not yet supported (API doesn't support skills yet).
Meta-Analyzer Evaluation
The Meta-Analyzer provides intelligent second-pass analysis to improve signal-to-noise ratio.
Running Meta-Analyzer Comparison
# Compare performance with and without meta-analyzer
export SKILL_SCANNER_LLM_API_KEY=your_key
python evals/eval_runner.py --test-skills-dir evals/skills --use-llm --compare
Understanding Meta-Analyzer Impact
Example Comparison Output:
================================================================================
COMPARISON: Without Meta vs With Meta
================================================================================
Per-Skill Changes:
prompt-injection/jailbreak-override:
Before: 5 findings -> After: 2 findings (filtered 3)
Status: UNSAFE -> UNSAFE (threat detection maintained)
safe-skills/calculator:
Before: 2 findings -> After: 0 findings (filtered 2)
Status: UNSAFE -> SAFE (false positives removed!)
Summary:
Without Meta: 85.7% detection rate, 22 total findings
With Meta: 85.7% detection rate, 8 total findings
Noise Reduction: 64%
Why Metrics May Look "Worse" With Meta
When comparing raw metrics, meta-analysis may show:
- Fewer True Positives: Multiple related findings consolidated into one
- Lower Finding Count: Redundant/duplicate findings removed
- Different Severities: Normalized based on actual risk
Key Insight: The goal is same detection rate with fewer findings. If a skill has 5 prompt injection findings that all describe the same attack, consolidating to 1 finding is better for actionability.
What Meta-Analyzer Does
- False Positive Pruning: Removes findings that are likely false alarms
- Finding Consolidation: Merges related findings into single actionable items
- Priority Ranking: Assigns priority to help focus on critical issues first
- Confidence Enrichment: Adds validation status based on full skill context
Summary
To improve precision/recall:
- [OK] Update
_expected.jsonfiles to include ALL legitimate threats found by analyzers - [OK] Use the helper script (
update_expected_findings.py) to identify gaps - [OK] Match expected severities to what analyzers actually report
- [OK] Be comprehensive - include all threat categories/severities, not just primary ones
- [OK] Use
--show-aitechto verify threat taxonomy alignment - [OK] Use
--compareto evaluate meta-analyzer effectiveness
The evaluation framework is working correctly - the issue is that expected findings are incomplete. Once you update them to match actual findings, precision/recall will improve significantly!