Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NanoSIEM

A production-grade, minimal-dependency SIEM engine built from scratch in Python.

CI Python 3.10+ License: MIT Tests STIX 2.1

Sigma detection Β· Attack chain correlation Β· ML anomaly scoring Β· STIX 2.1 export


What is NanoSIEM?

NanoSIEM is a fully functional SIEM engine written in ~4,500 lines of pure Python. It implements the same detection pipeline used by enterprise security platforms β€” but without the abstraction fog. Every component is readable, testable, and documented.

Built as a learning-by-doing alternative to studying SIEM theory. If you want to understand how detection engineering actually works at the code level, read this codebase.

Log sources β†’ Parse β†’ Normalize β†’ Sigma Eval β†’ Correlate β†’ ML Score β†’ Alert β†’ STIX 2.1

Feature Matrix

Capability Detail
Log Ingestion Syslog RFC 5424, Syslog RFC 3164, CEF, JSON, plaintext β€” auto-detected
Transport UDP syslog, TCP syslog (RFC 6587), TCP JSON, local file tail
Sigma Engine Custom AST parser β€” and/or/not/1 of/all of, field modifiers (contains, startswith, endswith, re)
Correlation 6 built-in attack chains, sliding time-window, source-IP grouped, deduplication
ML Detection Isolation Forest, 31-feature extractor, percentile-calibrated scoring, XAI attribution
Alerting Unified alert manager, severity filtering, dedup by fingerprint
Output STIX 2.1 JSON bundles, NDJSON alert log, SQLite ring buffer
CLI run, tail, parse-line, stats commands via Typer
Tests 234 passing, 6 test modules covering all components
Dependencies pyyaml, stix2, scikit-learn, typer, rich, joblib β€” nothing else

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Log Sources                              β”‚
β”‚   UDP Syslog Β· TCP Syslog Β· TCP JSON Β· File Tail                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚  RawMessage queue (asyncio, bounded 10k)
                             β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Ingestion Pipeline                           β”‚
β”‚                                                                 β”‚
β”‚   parser.py          normalizer.py          schema.py           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚   β”‚RFC 5424  β”‚       β”‚ IP extract β”‚        β”‚NormalizedEventβ”‚    β”‚
β”‚   β”‚RFC 3164  │──────▢│ Username   │───────▢│  (common     β”‚    β”‚
β”‚   β”‚CEF       β”‚       β”‚ Auth tags  β”‚        β”‚   schema)    β”‚    β”‚
β”‚   β”‚JSON      β”‚       β”‚ Port parse β”‚        β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚   β”‚Plaintext β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚            β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                    β”‚            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                    β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
              β”‚                                     β”‚
              β–Ό                                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Sigma Rule Engine     β”‚           β”‚  Correlation Engine      β”‚
β”‚                         β”‚           β”‚                         β”‚
β”‚  loader.py              β”‚           β”‚  window.py              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚           β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ YAML β†’ SigmaRuleβ”‚   β”‚           β”‚  β”‚ Per-source deque β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚           β”‚  β”‚ Sliding window   β”‚    β”‚
β”‚           β”‚            β”‚           β”‚  β”‚ LRU eviction     β”‚    β”‚
β”‚  ast.py   β”‚            β”‚           β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚           β”‚           β”‚             β”‚
β”‚  β”‚ Condition β†’ AST β”‚   β”‚           β”‚  chainer.py             β”‚
β”‚  β”‚ and/or/not/1of  β”‚   β”‚           β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚           β”‚  β”‚ Sequence finder  β”‚    β”‚
β”‚           β”‚            β”‚           β”‚  β”‚ 6 built-in chainsβ”‚    β”‚
β”‚  evaluator.py          β”‚           β”‚  β”‚ Alert callbacks  β”‚    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚           β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚  β”‚ Walk AST vs     β”‚   β”‚           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚  β”‚ NormalizedEvent β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚   ML Anomaly Scorer     β”‚
                                      β”‚                         β”‚
                                      β”‚  features.py            β”‚
                                      β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
                                      β”‚  β”‚ 31-dim extractor β”‚    β”‚
                                      β”‚  β”‚ temporal/network β”‚    β”‚
                                      β”‚  β”‚ program/message  β”‚    β”‚
                                      β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
                                      β”‚           β”‚             β”‚
                                      β”‚  baseline.py            β”‚
                                      β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
                                      β”‚  β”‚ IsolationForest  β”‚    β”‚
                                      β”‚  β”‚ Calibrated score β”‚    β”‚
                                      β”‚  β”‚ XAI attribution  β”‚    β”‚
                                      β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                    β”‚
                                                    β–Ό
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚        Alert Manager            β”‚
                              β”‚                                 β”‚
                              β”‚  Sigma + Correlation + ML       β”‚
                              β”‚  Fingerprint deduplication      β”‚
                              β”‚  Severity routing               β”‚
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β–Ό                    β–Ό                    β–Ό
             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             β”‚STIX 2.1  β”‚       β”‚ NDJSON alert β”‚      β”‚  SQLite  β”‚
             β”‚ Bundles  β”‚       β”‚    log       β”‚      β”‚  Ring    β”‚
             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚  Buffer  β”‚
                                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quickstart

Install

git clone https://github.com/Sudeep72/nano-siem.git
cd nano-siem
pip install -e .

Run the demo (no setup required)

bash demo.sh

This runs all 5 detection phases against synthetic log data and shows real detections.

Start the live pipeline

# Terminal 1 β€” start nano-siem
nano-siem run

# Terminal 2 β€” send a simulated attack kill chain
bash examples/send_kill_chain.sh

Tail a local log file

nano-siem tail /var/log/auth.log

Parse and inspect a single log line

nano-siem parse-line '<34>1 2026-06-02T03:00:01Z web-01 sshd 1234 - - Failed password for root from 203.0.113.5 port 22'

Detection Layers

Layer 1 β€” Sigma Rule Evaluation

NanoSIEM ships with 7 built-in Sigma rules and supports loading any Sigma-compatible YAML:

Rule Level MITRE Technique
SSH Brute Force Attempt HIGH T1110.001
SSH Successful Login LOW T1021.004
Privilege Escalation via Sudo MEDIUM T1548.003
Port Scan Detected MEDIUM T1046
Web Admin Panel Access Attempt MEDIUM T1190
High Severity CEF Event HIGH β€”
Suspicious Root Process Execution HIGH T1059

Add your own rules in rules/ β€” any .yml file is auto-loaded.

Layer 2 β€” Attack Chain Correlation

6 built-in kill-chain patterns, source-IP grouped across a sliding time window:

Chain Steps Window Severity
Brute Force β†’ Successful Login 2 10 min CRITICAL
Port Scan β†’ Brute Force 2 5 min HIGH
Login β†’ Privilege Escalation 2 15 min CRITICAL
Port Scan β†’ Web Admin Probe 2 3 min HIGH
Full Intrusion Kill Chain 4 30 min CRITICAL
Repeated Auth Failures (Γ—3) 3 2 min MEDIUM

Layer 3 β€” ML Anomaly Detection

Isolation Forest trained on a 2000-event synthetic baseline of normal Linux traffic. 31-dimensional feature vector covering temporal, network, program, message, and severity signals. Detects threats with no rule coverage β€” including novel attack patterns.

XAI attribution explains every anomaly score with the top features driving it:

πŸ€– ML [ANOMALOUS] score=0.987 | drivers: is_error_severity=1.00, is_off_hours=0.84, dest_port_norm=0.67

Output

STIX 2.1 Bundles

Every alert produces a valid STIX 2.1 bundle in alerts/YYYY-MM-DD/:

{
  "type": "bundle",
  "spec_version": "2.1",
  "objects": [
    { "type": "indicator", "name": "SSH Brute Force Attempt", "confidence": 80 },
    { "type": "sighting",  "count": 3, "first_seen": "2026-06-02T03:00:01Z" },
    { "type": "observed-data", "custom_properties": {
        "x_nano_siem_severity": "high",
        "x_nano_siem_anomaly_score": 0.691,
        "x_nano_siem_xai_features": [{"feature": "has_failure_keyword", "deviation": 1.0}]
    }}
  ]
}

NDJSON Alert Log

alerts/alerts-YYYY-MM-DD.ndjson β€” one JSON object per line, easy to pipe to any downstream tool.


Configuration

All settings in config.yaml:

ingestion:
  syslog_host: "0.0.0.0"
  syslog_port: 5140
  syslog_protocol: "tcp"     # tcp | udp
  json_port: 5141

ml:
  train_on_startup: true
  anomaly_threshold: 0.62    # 0.0–1.0, higher = stricter

alerting:
  dedup_window_seconds: 300
  min_severity: "low"        # low | medium | high | critical
  stix_output: true

Sending Logs to NanoSIEM

# TCP Syslog (RFC 5424)
echo '<34>1 2026-06-02T03:00:01Z web-01 sshd - - - Failed password for root from 1.2.3.4' \
  | nc -q1 localhost 5140

# TCP JSON
echo '{"host":"web-01","process":"nginx","message":"GET /admin HTTP/1.1 403","level":"warn"}' \
  | nc -q1 localhost 5141

# CEF (via TCP syslog port)
echo 'CEF:0|Snort|IDS|2.9|1000001|Port Scan Detected|8|src=192.168.1.5 dst=10.0.0.1' \
  | nc -q1 localhost 5140

Running Tests

pip install pytest
python -m pytest tests/ -v
234 passed in 3.13s

Test coverage spans all 5 detection layers:

Module Tests
test_parser.py 27 β€” RFC5424, RFC3164, CEF, JSON, plaintext
test_normalizer.py 26 β€” field mapping, IP/port/user extraction, auth tagging
test_sigma.py 47 β€” loader, AST builder, evaluator, engine integration
test_correlation.py 42 β€” window buffer, step matching, chain detection
test_ml.py 50 β€” feature extraction, training, scoring, XAI
test_alerting.py 42 β€” alert construction, dedup, STIX output

Project Structure

nano-siem/
β”œβ”€β”€ nano_siem/
β”‚   β”œβ”€β”€ schema.py              # NormalizedEvent β€” the pipeline's common language
β”‚   β”œβ”€β”€ main.py                # Async pipeline orchestrator
β”‚   β”œβ”€β”€ ingestion/
β”‚   β”‚   β”œβ”€β”€ parser.py          # RFC5424 / RFC3164 / CEF / JSON / plaintext
β”‚   β”‚   β”œβ”€β”€ normalizer.py      # ParsedLog β†’ NormalizedEvent + field extraction
β”‚   β”‚   └── listener.py        # UDP, TCP syslog, TCP JSON, file tail listeners
β”‚   β”œβ”€β”€ sigma/
β”‚   β”‚   β”œβ”€β”€ loader.py          # Sigma YAML β†’ SigmaRule dataclass
β”‚   β”‚   β”œβ”€β”€ ast.py             # Detection block β†’ evaluable AST
β”‚   β”‚   └── evaluator.py       # AST evaluation + SigmaEngine
β”‚   β”œβ”€β”€ correlation/
β”‚   β”‚   β”œβ”€β”€ chains.py          # 6 built-in ChainRule definitions
β”‚   β”‚   β”œβ”€β”€ window.py          # Per-source sliding time-window buffer
β”‚   β”‚   └── chainer.py         # Sequence detection + Correlator
β”‚   β”œβ”€β”€ ml/
β”‚   β”‚   β”œβ”€β”€ features.py        # 31-dimensional feature extractor
β”‚   β”‚   β”œβ”€β”€ baseline.py        # IsolationForest trainer + corpus generator
β”‚   β”‚   └── scorer.py          # Per-event anomaly scoring + XAI
β”‚   β”œβ”€β”€ storage/
β”‚   β”‚   └── ringbuffer.py      # SQLite-backed event ring buffer
β”‚   β”œβ”€β”€ alerting/
β”‚   β”‚   β”œβ”€β”€ manager.py         # Alert dedup, severity routing
β”‚   β”‚   └── stix_output.py     # STIX 2.1 bundle serializer
β”‚   └── cli/
β”‚       └── app.py             # Typer CLI
β”œβ”€β”€ rules/sample/              # 7 built-in Sigma rules
β”œβ”€β”€ tests/                     # 234 tests across 6 modules
β”œβ”€β”€ examples/                  # Runnable usage examples
β”œβ”€β”€ config.yaml                # All configuration
└── demo.sh                    # End-to-end 5-phase demo

Performance

Benchmarked on a standard laptop (Python 3.13, single core):

Metric Value
Ingestion throughput ~55,000 events/sec
Parse + normalize latency 0.018 ms/event
Sigma evaluation (7 rules) ~0.05 ms/event
ML scoring (IsolationForest) ~0.1 ms/event
End-to-end pipeline latency < 0.5 ms/event
Memory (1000 sources, 500 events each) ~100 MB

Roadmap

See ROADMAP.md for the full version plan.

Version Focus Status
v1.0 Core detection platform βœ… Released
v2.0 Detection Engineering Edition πŸ”œ Planned
v3.0 SOC Operations Edition πŸ”œ Planned
v4.0 AI Reasoning Edition πŸ”œ Planned

Contributing

See CONTRIBUTING.md. All contributions welcome β€” especially new Sigma rules, correlation chain patterns, and additional log format parsers.


License

MIT β€” see LICENSE.


Built by Sudeep Ravichandran Β· Indiana University Bloomington, MS Cybersecurity Risk Management

About

Production-grade SIEM engine built from scratch - Sigma detection, attack chain correlation, ML anomaly scoring, and STIX 2.1 export.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages