How to Configure Custom YARA Rules for Threat Detection in SkillSpector

You can configure custom YARA rules in SkillSpector by supplying a directory containing .yar or .yara files via the --yara-rules-dir flag, which the static_yara analyzer automatically merges with the built-in signature set during every scan.

SkillSpector, NVIDIA's static analysis framework for AI skills, ships with a YARA-based analyzer that detects malware, webshells, and crypto-miners by default. When you need to identify additional threat patterns specific to your organization or use case, you can extend the tool with custom signatures that integrate seamlessly into the existing analysis pipeline. This guide explains exactly how to configure custom YARA rules by leveraging the rule-loading implementation in src/skillspector/nodes/analyzers/static_yara.py.

How Custom YARA Rules Work in SkillSpector

The YARA analyzer operates as a node in SkillSpector's analysis graph. By default, it loads the built-in rule set located under src/skillspector/yara_rules/, which contains signatures for common threats.

When you provide a custom directory via the CLI or Python API, the system stores the path in the shared state under the key "yara_rules_dir" (defined in [state.py](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py#L91) at line 91). The analyzer then invokes its internal _load_rules(extra_dir) helper to compile and cache your signatures alongside the built-in ones.

Step-by-Step Configuration Guide

1. Prepare Your Rule Directory

Create a directory containing one or more files with the extensions .yar or .yara. SkillSpector automatically discovers all rule files in this directory, requiring no manual registration of individual files.

mkdir my_custom_rules

2. Structure Rules with Required Metadata

Each custom rule must include specific metadata fields that SkillSpector uses to categorize findings. The _parse_meta function maps these values to the internal Severity enum. Include these four meta fields:

  • category: Classification of the threat (e.g., "malware", "suspicious")
  • severity: Impact level mapped to SkillSpector's severity system (e.g., "CRITICAL", "HIGH")
  • confidence: Float value between 0 and 1 indicating detection certainty
  • description: Human-readable explanation of the threat
cat > my_custom_rules/malicious_download.yar <<'EOF'
rule malicious_download {
    meta:
        category = "malware"
        severity = "CRITICAL"
        confidence = "0.9"
        description = "Detects suspicious downloader binaries"
    strings:
        $a = "wget" nocase
        $b = "curl" nocase
    condition:
        any of them
}
EOF

3. Execute Scans with Custom Rules

Via CLI:

The --yara-rules-dir flag (registered in [cli.py](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/cli.py#L202-L208) lines 202-208) passes your directory to the analysis state:

skillspector scan path/to/skill \
    --yara-rules-dir ./my_custom_rules \
    --format json \
    --output report.json

Via Python API:

For programmatic use, supply the yara_rules_dir parameter to the scan state constructor:

from skillspector.cli import _scan_state, _scan_multi_skill
from pathlib import Path

state = _scan_state(
    skill_path="path/to/skill",
    format="json",
    no_llm=True,
    yara_rules_dir=str(Path("./my_custom_rules").resolve()),
    verbose=False,
)
report = _scan_multi_skill(*state)
print(report["findings"])

The Rule Loading Pipeline

Understanding the internal mechanics helps debug issues with custom rule integration. The _load_rules method in static_yara.py processes custom directories through five distinct stages:

File Collection and Content Hashing

First, _collect_rule_files gathers rules from both the built-in directory and your custom path. The system then computes a content hash via _content_hash across all rule files. This hash enables module-level caching, ensuring SkillSpector only recompiles rules when file contents actually change.

Namespace Deduplication and Compilation

The _build_namespace_map function creates a namespace mapping that prevents naming collisions between your custom rules and the built-in set. The analyzer attempts bulk compilation using yara.compile(filepaths=...). If bulk compilation fails due to syntax errors in any single file, it falls back to per-file compilation, skipping invalid rules while loading the rest.

Match Processing

During the scan, _match_file applies the compiled yara.Rules object against each source file. For every match found, the system generates an AnalyzerFinding by extracting the metadata through _parse_meta and mapping the YARA severity values to SkillSpector's internal severity levels.

Debugging Your Custom Rules

To verify that SkillSpector correctly loads your signatures before running a full scan, you can manually invoke the rule loader:

from skillspector.nodes.analyzers import static_yara
from pathlib import Path

# Force a reload with your temporary directory

rules = static_yara._load_rules(Path("./my_custom_rules"))
print(f"Compiled {len(rules)} rule(s)" if rules else "No rules compiled")

The test suite in [tests/nodes/analyzers/test_static_yara.py](https://github.com/NVIDIA/SkillSpector/blob/main/tests/nodes/analyzers/test_static_yara.py) provides additional examples of valid rule structures and edge cases for the fallback compilation behavior.

Summary

  • Create a directory containing files with .yar or .yara extensions to hold your custom signatures.
  • Include mandatory metadata (category, severity, confidence, description) in every rule for proper finding categorization.
  • Use the --yara-rules-dir flag (CLI) or yara_rules_dir parameter (Python API) to point to your custom directory.
  • Rules merge automatically with the built-in set from src/skillspector/yara_rules/; namespaces are deduplicated to prevent collisions.
  • Compilation is cached based on content hash, and syntactically invalid rules are skipped rather than causing scan failures.

Frequently Asked Questions

What file extensions are supported for custom YARA rules?

SkillSpector recognizes files ending in .yar or .yara. The _collect_rule_files helper specifically filters for these extensions when scanning your custom directory, ignoring all other file types.

How does SkillSpector handle naming conflicts between custom and built-in rules?

The _build_namespace_map function assigns unique namespaces to each rule file, preventing name collisions during compilation. Your custom rules coexist with the built-in set without overwriting or conflicting with existing signatures.

Can I replace the built-in rule set entirely with my own rules?

No, the current implementation in static_yara.py always loads the built-in rules from src/skillspector/yara_rules/ and appends your custom directory to that collection. You cannot disable the built-in set via configuration; you can only extend it.

What happens if one of my custom YARA rules contains a syntax error?

The compilation process implements a fallback mechanism. If yara.compile fails when attempting to compile all rules in bulk, the system falls back to compiling files individually, skipping any files with syntax errors while loading valid ones. This ensures that a single broken rule does not prevent the entire scan from executing.

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 →