Skip to content

Repository files navigation

Secrust

Real-time security event correlation, in a single Rust process.
Write Sigma rules, feed it OCSF events, get alerts — no cluster, no JVM, no brokers.

CI MIT licence Rust 1.70+ Sigma OCSF

Secrust ingests OCSF-compliant security events, evaluates them against detection rules, and emits alerts — inside one process, across all your cores. It borrows Apache Flink's ideas about stream processing (event time, keyed state, windows) without asking you to run Flink.

See it work

git clone https://github.com/BlueSquadron/Secrust.git
cd Secrust
./scripts/demo.sh

That replays a seeded attack — a brute force that succeeds, beaconing, tampered audit logs, a password spray — through a five-file rule pack covering all four detection strategies. Real output, no mock-ups:

Secrust demo — detections

Seven alerts from 27 events. The interesting one is lateral_movement: no single event is suspicious, but many failures followed by a success for the same user is an account takeover, and only a correlation rule can say so.

Before the replay, the demo shows the rules it compiled and the worker layout the engine derived from them — you never configure threads or partitions yourself:

Secrust demo — rules and worker layout

Everything it just ran lives in demo/: commented rules, the seed events, and a walk-through of the scenario minute by minute. Change a threshold, add an event, run it again.

Why Secrust

One binary, all cores The engine reads your rules, then builds its own worker pools: stateless rules run inline on the submitting thread, keyed counters get hash-partitioned pools, stateful state that must not be split gets a single worker.
Sigma in, alerts out Detection rules are Sigma YAML — including multi-document correlation rules — so they are reviewable, diffable and portable. Native JSON rules for machines.
OCSF-native Events follow the Open Cybersecurity Schema Framework, so anything that speaks OCSF speaks Secrust.
Event time, not arrival time Replaying yesterday's logs produces exactly the alerts that would have fired yesterday.
Embeddable Rust API, C FFI (Python, Go, Java, Node.js) or gRPC — pick one. Alerts go wherever you send them via the AlertSink trait.
Fast enough to stop thinking about it ~700K events/sec on a laptop for a mixed rule set, 1.1M+/sec for stateless matching — on one machine, no tuning.

Four ways to detect

Strategy Sigma shape Fires when
Value match no timeframe an event matches a field pattern (wildcards, regex, contains/startswith/endswith)
Counter timeframe + count(...) N matching events within a duration, optionally per key
Tumbling window timeframe a fixed window collects N events, or N distinct values of a field
Correlation correlation: document several rules fire for the same entity within a timespan — in any order (temporal) or in sequence (temporal_ordered)

The rule that catches the takeover in the demo:

title: Brute Force Followed by Successful Logon
id: lateral_movement
correlation:
    type: temporal_ordered
    rules:
        - logon_failures        # counter: >= 5 failures in 10m
        - logon_success         # counter: >= 1 success  in 10m
    group-by:
        - user.name
    timespan: 10m
    generate: false             # only the correlation alert is emitted

Full syntax: docs/detection-rules.md. Sharp edges worth five minutes: docs/gotchas.md.

Use it in your own code

Rust
use secrust::engine::EngineBuilder;
use secrust::models::Alert;
use secrust::traits::{AlertSink, AlertSinkError};
use std::path::Path;

struct Stdout;
impl AlertSink for Stdout {
    fn receive_alert(&self, alert: &Alert) -> Result<(), AlertSinkError> {
        println!("[{}] {} — {} event(s)", alert.timestamp, alert.rule_name, alert.matched_events.len());
        Ok(())
    }
}

let engine = EngineBuilder::new()
    .parallelism(4)
    .load_sigma_directory(Path::new("demo/rules"))?
    .add_alert_sink(Box::new(Stdout))
    .build()?;

engine.submit_event(r#"{
    "metadata": {"version": "1.1.0"},
    "severity_id": 5, "class_uid": 3001, "category_uid": 3,
    "activity_id": 2, "type_uid": 300102,
    "time": 1773478980000,
    "user": {"name": "mallory"},
    "src_endpoint": {"ip": "203.0.113.66"}
}"#)?;

engine.shutdown()?;   // drains in-flight events, then joins every thread

Add the dependency with secrust = { git = "https://github.com/BlueSquadron/Secrust" } (the crate is not on crates.io yet).

Python, Go, Java, Node.js — via the C FFI
cargo build -p secrust-ffi --release   # → target/release/libsecrust_ffi.{dylib,so,dll}
import ctypes, json

lib = ctypes.CDLL("target/release/libsecrust_ffi.dylib")
ALERT_CB = ctypes.CFUNCTYPE(None, ctypes.c_char_p, ctypes.c_void_p)

def on_alert(alert_json, _user_data):
    print("ALERT", json.loads(alert_json.decode())["rule_id"])

config = json.dumps({"parallelism": 4, "rules": {"rules": [
    {"type": "value_match", "id": "critical", "name": "Critical",
     "field": "severity_id", "pattern": "5"}]}})

engine, err = ctypes.c_void_p(), ctypes.c_char_p()
lib.sec_engine_new(config.encode(), ALERT_CB(on_alert), None,
                   ctypes.byref(engine), ctypes.byref(err))

Full C API in docs/developer-guide.md.

Any language — via gRPC
brew install protobuf     # or: apt install protobuf-compiler
make server               # listens on [::1]:50051

SubmitEvent, SubmitEventStream, SubscribeAlerts, GetCounterStates, GetWindowStates, Shutdown — schema in secrust-server/proto/secrust.proto.

Performance

Single run on an Apple Silicon laptop, release build, 100K OCSF authentication events per scenario. The quick one, ./scripts/demo.sh --bench:

throughput benchmark

The full matrix, from cargo run -p secrust --release --example parallelism_research (p = worker threads per keyed pool):

Workload p=1 p=2
Value match only (stateless) 1,154K/sec 1,580K/sec
Counter, ungrouped (singleton pool) 1,739K/sec 1,728K/sec
Counter, 256 distinct keys 802K/sec 1,508K/sec
Mixed (value match + counter + window) 701K/sec 1,038K/sec
Mixed + temporal correlation 702K/sec 1,074K/sec

Past p=2 the numbers flatten or dip: fan-out cost grows with pool count while the submitting thread stays the bottleneck. docs/parallelism-research.md has the analysis, the optimization history (+301% over eight stages) and the next bottlenecks — a good map if you want to make it faster.

How it works

submit_event(json)
  ├── single-pass serde parse (no flatten buffering)
  ├── value match rules evaluated inline, zero allocation
  └── Arc<Event> fan-out to the pools the rules asked for:
       ├── singleton pool (1 worker) — ungrouped counters, windows, correlations
       └── keyed pool(s) (N workers) — counters grouped by hash(field)
                                        ↓
                              alerts → dispatcher thread → your AlertSink(s)
secrust/          engine, evaluators, Sigma translation, worker pools
  examples/demo.rs  the guided demo you ran above
secrust-ffi/      C ABI shared library
secrust-server/   gRPC server (tonic)
demo/             seed events + commented rule pack
rules/            a handful of standalone example rules
docs/             guides, internals, research

Deeper: docs/internals.md — pipeline, thread model, channels, state expiry.

Build and test

cargo test -p secrust   # 163 tests: 141 unit, 8 integration, 14 property (~15s)
make build              # debug build, whole workspace
make bench-throughput   # quick events/sec report
make server             # gRPC server on [::1]:50051
make doc                # rustdoc

Rust 1.70+ (rustup update stable) is all you need for the library, the tests and the demo. protoc is required only to build secrust-server (brew install protobuf / apt install protobuf-compiler) — the workspace-wide targets (make build, make test) include it, so install it or scope your commands with -p secrust.

Contributing

Issues and pull requests are welcome — detection rules, docs and benchmarks just as much as engine code. CONTRIBUTING.md explains the layout, how to run the checks, and what a good rule contribution looks like; docs/gotchas.md doubles as a list of known limitations if you are looking for something to fix.

Everyone taking part is expected to follow the Code of Conduct. Security issues: please read SECURITY.md first.

Documentation

Guide What is in it
demo/README.md The demo pack, the seeded scenario, how to modify it
Detection rules Sigma and JSON rule syntax, every rule type
Gotchas Verified sharp edges and current limitations
Developer guide Event format, Rust API, C FFI, gRPC
Internals Architecture, pipeline, thread and channel design
Parallelism research Benchmarks and optimization history
ATT&CK coverage Detection coverage vs. MITRE ATT&CK
Flink comparison What Secrust does and does not take from Flink

Licence

MIT — see LICENSE.

About

Rewrite of SEC(Simple Event Correlator) in Rust Hopefully adding threading and some few more features

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages