Scoring & Alerting#
Starting with v2.2, Melissae replaces the continuous weighted-signal scoring engine with a rule-based alerting engine. Detection logic now lives in declarative YAML rules under rules/, and each observed IP’s verdict is the sum of the scores of every rule that matched its activity, capped at 100.
Scale & Verdicts#
Scores still use a 0–100 scale. Verdict thresholds are unchanged:
Range |
Verdict |
Description |
|---|---|---|
0–29 |
Benign |
Passive noise, single low-value connections |
30–69 |
Suspicious |
Active scanning, failed auth, reconnaissance |
70–100 |
Malicious |
Compromise, post-exploitation, ICS tampering, confirmed CVE exploitation |
Rule Format#
Each rule is a YAML file under rules/ (one file per rule, named MLSxxx.yml):
id: MLS008
name: SSH brute-force attempt
description: >
Multiple SSH authentication failures from the same IP within a short
window. Indicates credential-stuffing or brute-force activity.
severity: high
enabled: true
schedule: "*/1 * * * *"
lookback: 1m
mql: 'protocol:ssh AND action:Failed'
group_by: ip
threshold: 3
score: 40
tags: [brute-force, credential-access]
mitre: [T1110]
Field |
Meaning |
|---|---|
|
Stable rule identifier (e.g. |
|
Human-readable label and longer explanation surfaced in the dashboard. |
|
One of |
|
Boolean; disabled rules are loaded but never evaluated. |
|
Cron expression controlling how often the rule is re-evaluated by |
|
Time window scanned at each run ( |
|
Detection query in Melissae Query Language (the same DSL as the dashboard search bar). |
|
Aggregation key (typically |
|
Minimum number of matching events in the window required to emit an alert. |
|
Points contributed to the per-IP verdict when the rule fires. |
|
Free-form tags and MITRE ATT&CK technique IDs for classification. |
Built-in Rules#
Twelve rules ship with v2.2, covering the signals previously hard-coded in the scoring engine:
ID |
Detection |
Severity |
Score |
Notes |
|---|---|---|---|---|
MLS001 |
CVE exploitation attempt ( |
critical |
70 |
Any hit on a CVE-tagged module |
MLS002 |
FTP brute-force ( |
high |
30 |
≥5 failures / 5 min |
MLS003 – MLS007 |
Successful logins, post-exploitation commands, multi-protocol activity, … |
varies |
varies |
See |
MLS008 |
SSH brute-force ( |
high |
40 |
≥3 failures / 1 min |
MLS009 – MLS011 |
Modbus reads/writes, Telnet anomalies, … |
varies |
varies |
See |
MLS012 |
Nmap scan ( |
low |
5 |
User-agent based recon detection |
The complete set of rules — including exact MQL queries, thresholds and scores — is the source of truth in the rules/ directory and is also exposed by the API at GET /api/rules.
How Scoring Works#
rule_engine.pyloads every YAML file inrules/(configurable viaMELISSAE_RULES_DIR).For each enabled rule whose
scheduleis due, it pulls the logs of the lastlookbackwindow, runs themqlquery against them and groups the matches bygroup_by.Every group with at least
thresholdmatches produces an alert in MongoDB (alertscollection) carryingrule_id,severity,score,ip, time range and matching log references.threatIntel.pyaggregates alerts (rolling 90-day window) per IP into thethreatscollection. The verdict score is the sum of distinct rule scores, capped at 100; the verdict label follows the table above.The dashboard consumes
threats(Threat Intelligence, Map) andalerts(Alerts page) to drive its views.
This design makes detection logic transparent and auditable: every score increment is traceable to a specific rule, and operators can enable/disable, retune or extend rules without touching engine code.
Melissae Query Language (MQL)#
MQL is the small DSL used both by the dashboard search bar and by the mql field of each rule. Supported features:
Field-scoped terms —
protocol:ssh,action:"Login failed",ip:1.2.3.4,cve:CVE-2026-24061,user:root,user-agent:nmap,path:/admin,hour:14,date:2026-05-09,agent:my-agent.Free-text terms — bare words match against any field.
Boolean operators —
AND/OR/NOT(alsoand/or/!), with parenthesized grouping.Quoted values —
"Login failed"to match phrases containing spaces.
Examples#
protocol:ssh AND action:Failed
protocol:ftp AND action:"Login failed"
protocol:modbus AND action:write
cve:CVE
protocol:http AND nmap
ip:192.168.1.10 AND NOT action:successful