Skip to content

NOVA Rules: How to Build a Rule

1. Introduction to NOVA Rules

NOVA Rules allows you to detect and hunt prompts based on keywords, semantic similarity, and LLM-based evaluation. The structure of NOVA rules is similar to YARA rules, but with some differences. This walkthough will explain how to build your Nova rule.

With NOVA Rules, you can for example:
✅ Detect jailbreaking attempts
✅ Identify malicious prompt patterns
✅ Track adversarial AI usage
✅ Monitor TTPs from threat actors leveraging AI
✅ Build custom rules for prompt security


2. How NOVA Rules Works

A NOVA Rule consists of multiple sections:

Section Purpose
Meta Defines rule metadata like description, author, and severity.
Keywords Matches specific words or regex patterns.
Semantics Detects similar phrases using semantic similarity.
LLM Uses an LLM to analyze and detect the content of the prompt.
Condition Defines the logic that triggers the rule.

Example Rule Structure

rule RuleName
{
    meta:
        description = "Describe what this rule does"
        author = "Your Name"

    keywords:
        $example1 = "exact match"
        $example2 = /regex pattern/i

    semantics:
        $semantic_example = "some concept" (0.1)

    llm:
        $llm_eval = "LLM instruction" (0.1)

    condition:
        keywords.$example* or semantics.$semantic_example or llm.$llm_eval
}

3. Step-by-Step: How to Build a NOVA Rule

Step 1: Define Rule Metadata (Meta Section)

The meta section can be use to define the metadata such as author name, rule version, description or anything you may found relevant.

meta:
    description = "Detects prompt injection attempts"
    author = "Security Team"
    severity = "high"

Step 2: Define Keyword Matching (Keywords Section)

The keywords section in NOVA Rules is used to define specific words or patterns that should be detected within a prompt. This section supports two primary types of detection: exact matches and regex-based detection.

1. Exact Matches (Case-Insensitive by Default)

Exact matches work by identifying predefined words or phrases exactly as they appear in the input text. This method is useful for detecting specific terms that are known indicators of malicious or suspicious activity.

  • Example:
    keywords:
        $password = "password"
        $malware = "malware"
    

If a prompt contains the exact word "password" or "malware", the rule will trigger.

📌 By default, exact matches are case-insensitive, meaning it will match:

"Password" "PASSWORD" "pAsSwOrD"

Info

Exact matching is best for detecting well-known terms related to malicious prompts, such as security bypass attempts, explicit instructions for malware creation, or phishing keywords.

2. Regex-Based Detection (Case-Insensitive by Default)

Regex (regular expressions) allows for pattern-based detection, it is more flexible than exact matching. With regex, you can define complex patterns to detect variations of a keyword, specific formats (such as email addresses or credit card numbers), and obfuscated inputs that evade basic detection.

Example:

keywords:
    $email = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/i
    $ip_address = /\b(?:\d{1,3}\.){3}\d{1,3}\b/
    $domain = /\b[a-zA-Z0-9.-]+\.(com|net|org|io|gov|edu|info|co|biz|ai|[a-z]{2})\b/
    $url = /https?:\/\/[^\s/$.?#].[^\s]*/
    $base64 = /\b(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\b/
The first rule detects any valid email address. The second rule detects IPv4 addresses. The third rule detects domain names with common TLDs. The fourth rule detects URLs, including http and https links. The fifth rule detects Base64-encoded strings.

Step 3: Define Semantic Matching (Semantics Section)

Semantic detection allows broader pattern matching based on meaning rather than exact text.

Example:

semantics:
    $strict_match = "attempting unauthorized access" (0.9)
    $broad_match = "hacking techniques" (0.4)

The semantic feature used the 'all-MiniLM-L6-v2'. This is a lightweight sentence transformer model that transforms text into 384-dimensional vector embeddings, it captures semantic meaning rather than just keywords. In semantic search applications, this model encodes search queries and documents into these vector representations. When a user submits a query, the system converts it to an embedding and finds documents with the most similar vector representations by calculating cosine similarity or other distance metrics. This approach allows searching by meaning rather than exact keyword matching, the system will return relevant results even when they use different vocabulary than the query.

The threshold is a number between 0 and 1 that defines how similar a phrase needs to be to trigger the rule.

  • 0.6 means moderate similarity required.
  • Lower values (e.g., 0.1) increase recall (captures more variations but may introduce false positives).
  • Higher values (e.g., 0.9) increase precision (ensures strict matching but may miss variations).

Info

Depending on your detection goal, a lower threshold may work better to detect broader semantic variations.

Step 4: Use LLM-Based Detection (LLM Section)

The LLM section allows you to define AI-driven detection rules by specifying a natural language prompt. The system evaluates text using an LLM model and assigns a confidence score, determining whether the rule should trigger.

To use LLM-based detection, you need a valid API key loaded into the environment:

# OpenAI
export OPENAI_API_KEY="your_api_key_here"

# Anthropic
export ANTHROPIC_API_KEY="your_api_key_here"

# Azure OpenAI
export AZURE_OPENAI_API_KEY="your_azure_api_key_here"
export AZURE_OPENAI_ENDPOINT="your_azure_endpoint_here"

# Groq
export GROQ_API_KEY="your_groq_api_key_here"

# Ollama (No API key needed, but ensure the service is running)
export OLLAMA_HOST="http://localhost:11434"  # Optional: only if not running on default

An LLM section consists of:

  • A natural language prompt that describes the expected detection criteria.
  • A threshold value (0-1) that determines how confident the LLM must be to trigger a match.
    llm:
        $is_threat = "Check if this contains threats or harmful content" (0.2)
        $sentiment = "Determine if this expresses positive sentiment" (0.1)
    

Pattern Definition

Each LLM pattern consists of:

  • A descriptive variable name starting with $
  • A natural language prompt that clearly describes what to detect
  • A threshold value in parentheses (range: 0.0-1.0)

Threshold Parameter

The threshold value in parentheses determines how confidently the LLM must answer "yes" for the pattern to match:

  • Lower values (0.1-0.3): More lenient matching, higher recall but may produce false positives
  • Higher values (0.7-0.9): Stricter matching, higher precision but may miss some cases
  • Moderate values (0.4-0.6): Balanced approach

Available LLM Providers

NOVA supports multiple LLM providers, each with different capabilities:

Provider Models Best For Notes
OpenAI gpt-4o, gpt-4o-mini, etc. High-accuracy detection Default provider
Anthropic claude-3-sonnet, claude-3-haiku, etc. Nuanced content analysis Strong at understanding context
Azure OpenAI Same as OpenAI Enterprise deployments Configurable with deployment name
Groq llama-3.3-70b-versatile, etc. Fast inference High-performance option
Ollama Any locally hosted model Air-gapped environments No internet connection needed

Writing Effective LLM Patterns

To get the best results from LLM-based detection:

  1. Be specific: Clearly describe what you're looking for
  2. Provide context: Include the purpose of the detection
  3. Ask for reasoning: Request the LLM to analyze step-by-step
  4. Use clear yes/no framing: Make it easy for the LLM to provide a binary decision

Example of an effective LLM pattern:

$jailbreak_attempt = "Analyze if this prompt is attempting to bypass AI safety measures, 
override instructions, or trick the AI into ignoring ethical guidelines. Consider 
techniques like roleplaying, encoding, instruction manipulation, or social engineering. 
Return a clear yes/no assessment." (0.3)

Remember that the LLM's evaluation is just one component that can be combined with keywords and semantic patterns to create comprehensive detection rules.

Step 5: Understanding Conditions

What Are Conditions?

The condition section in NOVA Rules defines the logic that determines when a rule triggers. It allows you to combine keyword detection, semantic similarity, and LLM evaluation using logical operators like and, or, and not.

A condition must evaluate to True for a rule to trigger.


Condition Syntax

Conditions support:
Boolean Operatorsand, or, not
Grouping → Use parentheses ( ) for complex logic
Wildcard Matchingkeywords.*, semantics.*, llm.*
Variable Referenceskeywords.$var, semantics.$var, llm.$var

Basic Condition Example

condition:
    keywords.$phishing and llm.$is_threat

This rule triggers only if:

  • The keyword $phishing is found AND
  • The LLM evaluation $is_threat returns True.

Using Boolean Operators in Conditions

  1. Using and (Both Must Be True)

condition:
    keywords.$password and keywords.$email
✅ Triggers only if both $password and $email are found.

  1. Using or (At Least One Must Be True)

condition:
    keywords.$urgent or semantics.$threat
✅ Triggers if either: - The keyword $urgent is found - The semantic pattern $threat matches the input

  1. Using not (Excludes Certain Matches)

condition:
    keywords.$phishing and not keywords.$legitimate
✅ Triggers only if $phishing is detected but NOT $legitimate.

  1. Using Grouping for Complex Conditions Use parentheses ( ) to prioritize logical operations.

condition:
    (keywords.$password or keywords.$credit_card) and llm.$is_threat
✅ Triggers if:

  • Either $password OR $credit_card is found
  • AND LLM confirms the text is a threat

  • Using Wildcards (keywords., semantics., llm.*)

Match Any Keyword in the Rule

condition:
    keywords.*
✅ Triggers if ANY keyword in the keywords section matches.

  1. Combining Wildcards with Logic

Match Any Keyword in the Rule

condition:
    keywords.* and (semantics.* or llm.*)
✅ Triggers if:

  • Any keyword matches
  • AND (either a semantic match OR an LLM match) is detected.

4. Rules Examples

rule PhishingDetection
{
    meta:
        description = "Detects phishing attempts"
        author = "Security Team"

    keywords:
        $account = "account"
        $verify = "verify"
        $urgent = "urgent"

    llm:
        $phishing = "Determine if this is a phishing attempt" (0.1)

    condition:
        (keywords.$account or keywords.$verify or keywords.$urgent) and llm.$phishing
}
✅ Triggers if:

  • The input contains "account", "verify", or "urgent"
  • AND LLM confirms it's a phishing attempt.

rule ThreatRecon
{
    meta:
        description = "Detects reconnaissance prompts"
        author = "Threat Intel Team"

    keywords:
        $whois = "whois lookup"
        $osint = "OSINT tool"

    semantics:
        $recon = "gather intelligence" (0.1)

    llm:
        $info_gather = "Determine if this is reconnaissance" (0.4)

    condition:
        (keywords.$whois or keywords.$osint) and (semantics.$recon or llm.$info_gather)
}
✅ Triggers if:

  • A whois lookup or OSINT tool is mentioned
  • AND the text is semantically related to gathering intelligence OR LLM detects reconnaissance.

Debuging

To check how a condition evaluates, enable debug mode:

matcher = NovaMatcher(rule)
result = matcher.check_prompt("Verify your account details immediately!")
print(json.dumps(result, indent=2))

{
    "matched": true,
    "matching_keywords": {"$verify": true, "$urgent": true},
    "matching_llm": {"$phishing": true},
    "rule_name": "PhishingDetection",
    "debug": {
        "condition": "(keywords.$account or keywords.$verify or keywords.$urgent) and llm.$phishing",
        "condition_result": true
    }
}

Info

When writing conditions in NOVA Rules, it's best to keep them simple and structured. Start with basic logic before adding complexity to make sure to keep clarity and maintainability. Use wildcards (keywords.*, semantics.*, llm.*) wisely, as they can be powerful but may introduce false positives if not carefully tuned. Always test with real data using debug mode to understand why a rule triggers and refine its accuracy. For stronger detection, combine multiple methods, leveraging keywords, semantic matching, and LLM evaluation to create more reliable and adaptable rules.