AI-Assisted Detection: LLMs for Sigma Rule Generation
Integrating Large Language Models into detection engineering is one of the most significant shifts in the SOC landscape of recent years. This is not simply about automating a repetitive task: using an LLM to generate Sigma rules means compressing into seconds a process that an experienced analyst completes in hours, from reading a threat report to writing a tested, deployment-ready rule.
Frameworks like SigmaGen, presented at MITRE ATT&CK APAC 2025, demonstrate how fine-tuned models can ingest threat intelligence reports, extract ATT&CK techniques, and produce accurately mapped Sigma rules. At the same time, open-source tools and n8n-based workflows allow smaller teams to build AI-assisted pipelines without enterprise-level investment.
This article walks you through the architecture of an AI-assisted system for detection rule generation: from prompt engineering, to automatic validation, to testing with synthetic logs, and finally integration into an existing CI/CD pipeline.
What You Will Learn
- Why LLMs reason better over Sigma format than direct SPL output
- Prompt engineering techniques specific to detection rule generation
- Architecture of an end-to-end AI-assisted pipeline
- Automatic validation and testing of generated rules
- Integration with SigmaGen, pySigma and CI/CD workflows
- Anti-patterns to avoid and real-world LLM limitations in security contexts
Why LLMs Excel at Generating Sigma Rules
One of the most interesting observations from applied research - confirmed in practice - is that LLMs produce significantly higher-quality output when generating Sigma compared to direct SPL or KQL queries. The reason is structural.
Sigma's YAML format enforces a clear separation between:
- title and description: the model must articulate what it is detecting and why
- logsource: specifies the data source (category, product, service)
- detection: the Boolean matching logic
- condition: how to combine the selectors
- falsepositives: explicit reasoning about edge cases
This structure forces the model to think sequentially and declaratively, reducing the logical errors that arise when asking directly for platform-specific query language output. In practice, Sigma acts as an implicit chain-of-thought for LLMs applied to detection.
Benchmark Data
Researchers on the LLMCloudHunter project (2024) demonstrated that generalist LLMs like GPT-4 generate valid Sigma rules in 73% of cases on structured CTI reports, compared to 41% when asking for direct SPL output. The rate rises to 89% with fine-tuning on security-specific datasets.
AI-Assisted Pipeline Architecture
An AI-assisted pipeline for detection rule generation consists of five distinct stages:
- Ingestion: ingesting threat reports, CTI blog posts, CVE advisories
- Extraction: extracting IOCs, ATT&CK techniques, described behaviors
- Generation: generating the Sigma rule via LLM
- Validation: automatic syntactic and semantic validation
- Testing: testing with synthetic logs and CI/CD integration
# Base architecture of the AI-assisted pipeline
# File: ai_sigma_pipeline.py
import openai
import yaml
from pathlib import Path
from dataclasses import dataclass
from typing import Optional
@dataclass
class ThreatReport:
content: str
source_url: str
report_type: str # 'cti_blog', 'advisory', 'malware_analysis'
@dataclass
class GeneratedRule:
sigma_yaml: str
mitre_techniques: list[str]
confidence: float
validation_passed: bool
test_results: Optional[dict] = None
class AISigmaPipeline:
def __init__(self, openai_api_key: str, rules_output_dir: str):
self.client = openai.OpenAI(api_key=openai_api_key)
self.output_dir = Path(rules_output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
def process_report(self, report: ThreatReport) -> list[GeneratedRule]:
"""Full pipeline from report to validated rules."""
techniques = self._extract_attack_techniques(report)
behaviors = self._extract_behaviors(report)
rules = []
for technique in techniques:
rule = self._generate_sigma_rule(
report=report,
technique=technique,
behaviors=behaviors
)
if rule:
rules.append(rule)
return [self._validate_and_test(r) for r in rules]
def _extract_attack_techniques(self, report: ThreatReport) -> list[str]:
"""Extracts ATT&CK techniques from the report via LLM."""
response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": (
"You are a threat intelligence analyst expert in MITRE ATT&CK. "
"Extract ONLY ATT&CK techniques (format T1234 or T1234.001) "
"explicitly described in the text. Reply only with a JSON list."
)
},
{
"role": "user",
"content": f"Report:\n{report.content[:4000]}"
}
],
temperature=0.1
)
import json
try:
return json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
return []
Prompt Engineering for High-Quality Sigma Rules
Output quality critically depends on prompt structure. Three fundamental patterns produce consistent results in Sigma rule generation:
Pattern 1: Structured System Prompt
The system prompt must contain exactly the meta-information the model needs to generate valid Sigma:
the YAML structure, valid values for category and product, best practices for
falsepositives, and allowed severity levels.
# Optimized system prompt for Sigma rule generation
SIGMA_SYSTEM_PROMPT = """
You are a Detection Engineer expert in writing Sigma rules.
When generating a Sigma rule, ALWAYS follow this YAML structure:
title: [descriptive title, max 80 chars]
id: [UUID v4]
status: experimental
description: [detailed description of the detected behavior]
author: AI-Assisted Detection
date: [today's date YYYY-MM-DD]
tags:
- attack.[tactic]
- attack.[technique]
logsource:
category: [process_creation | network_connection | file_event | registry_event]
product: [windows | linux | macos]
detection:
[selector_name]:
[field]: [value or list of values]
condition: [selector_name]
falsepositives:
- [plausible legitimate cases]
level: [informational | low | medium | high | critical]
CRITICAL RULES:
- ALWAYS use wildcards (*) in string values to avoid brittle exact matches
- Prefer fields with high availability (Image, CommandLine, ParentImage)
- Always indicate at least one realistic false positive
"""
Pattern 2: Few-Shot with Quality Examples
Including 2-3 high-quality rule examples in the prompt dramatically improves output consistency, especially for unusual logsources or complex conditions.
Pattern 3: Explicit Chain-of-Thought
For complex techniques, asking the model to reason before writing the rule produces more accurate output. This approach adds latency but significantly reduces the number of iterations needed.
def generate_with_cot(self, technique_id: str, report: ThreatReport) -> str:
"""Generation with explicit Chain-of-Thought."""
# Step 1: Ask the model to reason first
reasoning_response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SIGMA_SYSTEM_PROMPT},
{
"role": "user",
"content": f"""Before writing the rule for {technique_id}, analyze:
1. What forensic artifacts does this technique leave in logs?
2. What is the most appropriate logsource?
3. Which fields have the highest signal/noise discrimination?
4. What are the most common false positives?
Report: {report.content[:2000]}"""
}
],
temperature=0.3
)
reasoning = reasoning_response.choices[0].message.content
# Step 2: Use the reasoning to guide generation
rule_response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SIGMA_SYSTEM_PROMPT},
{"role": "user", "content": f"Technical analysis:\n{reasoning}"},
{
"role": "assistant",
"content": "Based on this analysis, I will generate the optimal Sigma rule:"
},
{"role": "user", "content": "Proceed with YAML generation."}
],
temperature=0.1
)
return rule_response.choices[0].message.content
Automatic Validation of Generated Rules
An LLM can produce syntactically valid but semantically incorrect YAML: a non-existent logsource, a field with the wrong name, a condition that does not correctly reference the selectors. Automatic validation is the critical gate before a rule enters the repository.
import yaml
from sigma.rule import SigmaRule
from sigma.exceptions import SigmaError
import re, uuid
class SigmaRuleValidator:
VALID_CATEGORIES = {
'process_creation', 'network_connection', 'file_event',
'registry_event', 'dns_query', 'image_load', 'pipe_created'
}
VALID_LEVELS = {'informational', 'low', 'medium', 'high', 'critical'}
def validate(self, sigma_yaml: str) -> tuple[bool, list[str]]:
"""Validates a Sigma rule. Returns (valid, errors)."""
errors = []
try:
rule_dict = yaml.safe_load(sigma_yaml)
except yaml.YAMLError as e:
return False, [f"Invalid YAML: {str(e)}"]
# Required fields check
for field in ['title', 'description', 'logsource', 'detection']:
if field not in rule_dict:
errors.append(f"Missing required field: {field}")
if errors:
return False, errors
# Logsource validation
logsource = rule_dict.get('logsource', {})
if 'category' in logsource:
if logsource['category'] not in self.VALID_CATEGORIES:
errors.append(f"Invalid logsource category: {logsource['category']}")
# Detection/condition validation
detection = rule_dict.get('detection', {})
if 'condition' not in detection:
errors.append("Missing 'condition' field in detection")
# UUID validation
rule_id = rule_dict.get('id', '')
if rule_id:
try:
uuid.UUID(str(rule_id))
except ValueError:
errors.append(f"ID is not a valid UUID: {rule_id}")
# pySigma deep validation
try:
SigmaRule.from_yaml(sigma_yaml)
except SigmaError as e:
errors.append(f"pySigma error: {str(e)}")
return len(errors) == 0, errors
Anti-Pattern: Blindly Trusting LLM Output
A common mistake in teams implementing AI-assisted detection is deploying generated rules without validation. LLMs make specific and repeatable errors in Sigma generation:
- Using
ProcessNameinstead ofImage(Sysmon) - Writing conditions referencing non-existent selectors
- Inventing non-standard logsource categories
- Using
containson fields that do not support wildcards in the target logsource
Automatic validation and testing with real logs are NON-OPTIONAL.
Automated Testing with Synthetic Logs
After syntactic validation, every rule must be tested against logs that simulate both the expected malicious behavior (true positive test) and normal traffic (false positive test). This approach, called rule unit testing, is what distinguishes a mature pipeline from an experiment.
class SigmaRuleTester:
def generate_test_events(self, sigma_yaml: str, llm_client) -> dict:
"""Generates test events via LLM based on the rule."""
prompt = f"""Given this Sigma rule:
{sigma_yaml}
Generate in JSON format two event lists:
1. "true_positives": 3 events that MUST trigger the rule
2. "false_positives": 3 legitimate events that must NOT trigger
Format:
{
"true_positives": [{"Image": "...", "CommandLine": "..."}],
"false_positives": [{"Image": "...", "CommandLine": "..."}]
}"""
response = llm_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0.2
)
import json
try:
return json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
return {"true_positives": [], "false_positives": []}
Alternative Models and Cost Considerations
| Model | Sigma Quality | Cost per 100 rules | Avg. latency | Data residency |
|---|---|---|---|---|
| GPT-4o | High (87% valid) | ~$2.50 | 3-8s | Cloud (OpenAI) |
| GPT-4o-mini | Good (71% valid) | ~$0.15 | 1-3s | Cloud (OpenAI) |
| Claude 3.5 Sonnet | High (84% valid) | ~$3.00 | 3-6s | Cloud (Anthropic) |
| Llama 3.1 70B (local) | Fair (58% valid) | ~$0 (infra) | 15-45s | On-premise |
| Mistral 7B fine-tuned | Good (69% valid) | ~$0 (infra) | 5-15s | On-premise |
Cost-Effective Strategy
Use GPT-4o-mini for initial generation and retry iterations (low cost, good quality), and GPT-4o only when mini fails after 2 attempts. With this hybrid approach, the average cost drops to 30% compared to exclusive use of GPT-4o while maintaining comparable quality.
CI/CD Integration for AI-Generated Rules
Generated and validated rules do not go directly to production: they must pass through human review and CI/CD gates of the Detection-as-Code pipeline. The recommended flow has AI generate a Pull Request, not a direct merge.
# GitHub Actions for AI-generated rules
# .github/workflows/ai-sigma-generation.yml
"""
name: AI Sigma Rule Generation
on:
schedule:
- cron: '0 6 * * *'
jobs:
generate-rules:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with: { python-version: '3.12' }
- name: Run AI pipeline
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: python scripts/ai_sigma_pipeline.py
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
title: '[AI-Generated] Detection rules from CTI feed'
labels: 'ai-generated,needs-review'
"""
Conclusions and Next Steps
AI-assisted detection engineering is not a trend: it is an operational necessity for teams that need to keep pace with the speed at which new attack techniques emerge. The combination of LLMs for generation, rigorous automatic validation, and testing with synthetic logs allows reducing time-to-detection from days to hours on a freshly published threat report.
Related deep dive: 08 - Alert Triage Automation: Ridurre MTTD con Graph Analysis.
Related deep dive: 09 - Testing Detection Rules: Unit Testing per Logica di Sicurezza.
Key Takeaways
- LLMs produce higher-quality Sigma rules than direct SPL queries thanks to the YAML structure
- Prompt engineering (structured system prompt, few-shot, chain-of-thought) is critical for quality
- Automatic syntactic and semantic validation is non-optional
- Testing with AI-generated synthetic logs closes the quality loop
- Generated rules must go through human PR review, not automatic merge
- RAG with SIEM-specific context reduces field errors and false positives
- Local models (Llama, fine-tuned Mistral) are a valid alternative for data residency requirements
Related Articles
- Sigma Rules: Universal Detection Logic and SIEM Conversion
- Detection-as-Code Pipeline with Git and CI/CD
- Testing Detection Rules: Unit Testing for Security Logic
- Threat Intelligence Ingestion: STIX/TAXII Feed Processor
Frequently asked questions
What is the main advantage of using Large Language Models (LLMs) for generating Sigma rules?
LLMs can produce significantly higher-quality output when generating Sigma compared to direct SPL or KQL queries, due to their ability to think sequentially and declaratively.
What are some common mistakes teams make when implementing AI-assisted detection, and how can they be avoided?
Teams often deploy generated rules without validation, which can lead to specific and repeatable errors in Sigma generation. Automatic validation and testing with real logs are NON-OPTIONAL to ensure the accuracy of generated rules.
What is the recommended approach for using different LLM models to balance cost and quality in AI-assisted detection?
Using GPT-4o-mini for initial generation and retry iterations, and GPT-4o only when mini fails after 2 attempts, can reduce the average cost by 30% while maintaining comparable quality.
What is the recommended flow for integrating AI-generated rules into a Detection-as-Code pipeline?
The recommended flow has AI generate a Pull Request, not a direct merge, which allows human review and CI/CD gates to ensure the accuracy and reliability of generated rules.
Commenti
Caricamento commenti...
Sign in to comment