How the meta_analyzer Filters Static Findings in NVIDIA SkillSpector

The meta_analyzer is a graph node that post-processes raw static analysis results using an LLM to filter false positives, confirm vulnerabilities with granular line-level precision, and enrich findings with actionable explanations and remediation steps.

The NVIDIA SkillSpector framework employs a sophisticated post-processing stage to refine noisy static analysis outputs. At the heart of this refinement pipeline sits the meta_analyzer, a specialized node that transforms raw pattern-based detections into high-confidence, actionable security findings through LLM-powered validation and enrichment.

Core Responsibilities of the meta_analyzer

The meta_analyzer serves four critical functions in the SkillSpector analysis pipeline:

  • LLM-based filtering – It sends file content, manifest metadata, and raw static findings to a large language model via the LLMMetaAnalyzer class to determine vulnerability validity.
  • Granular confirmation – Using a unique granular key (file, rule_id, start_line, end_line), it matches LLM responses back to individual Finding objects, allowing independent acceptance or rejection of multiple findings sharing the same rule ID.
  • Enrichment – Confirmed findings receive LLM-generated explanations and remediation steps, replacing raw static output with human-readable context and updated confidence scores.
  • Fallback processing – When LLM usage is disabled or calls fail, it executes a deterministic pass-through that attaches default remediation strings to each finding.

Implementation in the SkillSpector Codebase

The core logic resides in src/skillspector/nodes/meta_analyzer.py, which implements both the entry point function and the LLM interaction layer.

The meta_analyzer Node Entry Point

The meta_analyzer() function (approximately line 556) serves as the primary graph node interface. This function inspects the pipeline state, builds batches of findings for processing, coordinates LLM calls, and returns the filtered list of validated findings. It operates on the shared SkillspectorState object, reading raw findings from static scanners and writing the refined results back to the state.

Granular Filtering with LLMMetaAnalyzer

The heavy lifting occurs within LLMMetaAnalyzer.apply_filter() (approximately line 670). This method implements the granular keying strategy that distinguishes individual findings even when they share the same rule ID within a single file. The key structure (file, rule_id, start_line, end_line) ensures precise alignment between the LLM's structured MetaAnalyzerResult responses and the original Finding objects.

When processing results, the analyzer checks the is_vulnerability flag and confidence score from each MetaAnalyzerResult, then enriches confirmed vulnerabilities with LLM-generated explanations and remediation steps. If the LLM provides specific line numbers, these override the original coordinates for higher precision.

Practical Code Examples

Invoking the meta_analyzer from a Pipeline

To integrate the filtering node into a SkillSpector workflow:

from skillspector.nodes.meta_analyzer import meta_analyzer
from skillspector.state import SkillspectorState

# Assume `state` already contains:

# - static analysis findings under the key "findings"

# - the skill manifest under "manifest"

# - a file cache mapping filenames → source code under "file_cache"

# - model configuration with the meta‑analyzer model name under "model_config"

filtered = meta_analyzer(state)          # returns {"filtered_findings": [...]}

print("Filtered findings:", len(filtered["filtered_findings"]))

Direct Use of LLMMetaAnalyzer for Single File Processing

For targeted analysis without the full pipeline:

from skillspector.nodes.analyzers.llm_analyzer_base import Batch
from skillspector.nodes.meta_analyzer import LLMMetaAnalyzer, _format_findings_for_prompt

# Example static findings for one file

static_findings = [...]  # list of skillspector.models.Finding objects

batch = Batch(
    file_path="skills/my_skill.py",
    file_label="my_skill.py",
    content=open("skills/my_skill.py").read(),
    findings=static_findings,
)

llm = LLMMetaAnalyzer(model="gpt-4o-mini")
prompt = llm.build_prompt(batch, metadata_text="Name: MySkill\nDescription: Demo")
print(prompt)                     # shows the exact prompt sent to the LLM

response = llm.run_sync(batch, metadata_text="Name: MySkill\nDescription: Demo")
filtered_items = llm.apply_filter(static_findings, [(batch, response)])

Fallback When LLM is Unavailable

To process findings without LLM dependency:

from skillspector.nodes.meta_analyzer import _fallback_filtered

# `findings` is the raw list from static scanners

fallback = _fallback_filtered(findings)

# each finding now carries the default remediation from `get_remediation()`

Supporting Components

The meta_analyzer relies on several key files within the SkillSpector repository:

Summary

The meta_analyzer transforms noisy static analysis dumps into actionable security intelligence by:

  • Leveraging LLM reasoning to validate static findings and eliminate false positives
  • Employing granular line-level keying to handle multiple findings per file independently
  • Enriching confirmed vulnerabilities with contextual explanations and remediation guidance
  • Providing deterministic fallback behavior when LLM services are unavailable

This architecture enables SkillSpector to surface only high-confidence vulnerabilities while maintaining detailed traceability to source code locations.

Frequently Asked Questions

What happens when the LLM is unavailable?

When LLM usage is disabled via use_llm=False or when the LLM call fails, the meta_analyzer executes a fallback path through _fallback_filtered(). This deterministic function attaches default remediation strings from pattern_defaults.py to each finding without filtering, ensuring the pipeline continues operating with baseline static analysis results.

How does the meta_analyzer handle multiple findings in the same file?

The meta_analyzer uses a granular key composed of (file, rule_id, start_line, end_line) to uniquely identify each finding. This allows the system to independently confirm or reject multiple occurrences of the same pattern within a single file, matching LLM responses precisely to the corresponding Finding objects based on line coordinates.

What data does the meta_analyzer send to the LLM?

For each batch, the LLMMetaAnalyzer transmits the file content, manifest metadata (skill name and description), and the formatted list of raw static findings. The build_prompt() method constructs this payload, and the LLM returns a structured MetaAnalyzerResult containing boolean flags, confidence scores, and optional corrected line numbers for each potential vulnerability.

How are findings enriched with explanations and remediation?

Confirmed findings undergo replacement of their default fields with LLM-generated content. The apply_filter() method extracts explanations and remediation steps from the LLM response and updates the Finding objects' explanation, remediation, and confidence attributes. If the LLM provides specific start and end lines, these override the original coordinates for higher precision reporting.

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 →