Skip to main content

Documentation Index

Fetch the complete documentation index at: https://wiki.krkn.tech/llms.txt

Use this file to discover all available pages before exploring further.

Mnemos — Correlation Engine

Mnemos is Aegis’ stateful request correlation engine. It detects attacks that span multiple HTTP requests from the same client within a configurable time window — the kind of campaigns that single-request WAF rules cannot catch. Mnemos is analogous to Snort’s flowbits + threshold + detection_filter, but operates at the HTTP application layer instead of the packet layer.
Image

Why Correlation Matters

Traditional WAF rules evaluate each request in isolation. Many real-world attacks look like a sequence of individually benign or low-severity requests that become dangerous only in aggregate:
  • OOB SQL Injection campaigns — a client probing multiple endpoints with LOAD_FILE, xp_dirtree, and DNS exfil patterns
  • Data exfiltration — systematically walking sensitive endpoints (/api/users, /api/billing, /api/config/export) with bulk extraction parameters
  • Credential stuffing — repeated login attempts with different usernames from the same IP
  • Scanner reconnaissance — schema probing followed by targeted injection attempts
Mnemos links these individual request signals into a single correlated detection event and escalates severity automatically.

How It Works

Architecture

Mnemos maintains an in-memory circular buffer of recent request history per client (keyed by host:source_ip). Every proxied request is recorded as a snapshot containing path, query, body, headers, user-agent, matched WAF rules, and action taken.
Request arrives
  |
  v
WAF rule chain evaluates (regex + condition rules)
  |
  v
Request snapshot recorded into Mnemos correlation store
  |
  v
Correlation rules evaluate against client history
  |
  v
If threshold met within window ──► correlation event fires

Core Components

ComponentDescription
CorrelationStoresync.Map of per-client circular buffers (default 64 entries per client, 5-minute TTL)
RequestSnapshotCaptured request and response data: timestamp, request ID, method, path, query, body (first 512 bytes), headers, cookies, user-agent, content-type, source IP, matched rules, action — plus response fields: status, size, content-type, latency, headers, body sample
Correlation RulesWAF rules with match_mode: correlated and a correlation_config block
Background GCPeriodic garbage collection removes stale client histories (2x TTL)

Evaluation Flow

When a correlation rule evaluates:
  1. Window — filter the client’s history to only snapshots within window_seconds of the current request
  2. Predicates — apply optional condition filters to narrow the snapshot set (e.g., only GET/POST requests to API paths)
  3. Trigger rules — check that the required WAF rules have fired within the window (all must be present, or in sequence if sequence_mode is enabled)
  4. Unique fields — if configured, count distinct values across the specified fields (e.g., unique paths) and compare against threshold
  5. Threshold — if the filtered snapshot count meets or exceeds the threshold, the correlation fires

Correlation Config Schema

Correlation rules use match_mode: correlated and require a correlation_config block:
FieldTypeRequiredDescription
window_secondsintegeryesTime window for correlation analysis (1–3600 seconds)
thresholdintegeryesMinimum number of matching requests required (minimum 2)
group_bystringnoGrouping key — currently only source_ip is supported
trigger_rulesarray of stringsnoWAF rule names that must have fired within the window
sequence_modebooleannoIf true, trigger rules must occur in the specified order
unique_fieldsarray of stringsnoCount unique values across these fields: path, query, body, user_agent
predicatesarray of objectsnoCondition filters applied to snapshots before evaluation

Predicate Object Schema

Predicates use the same field/operator/value structure as condition-based WAF rules:
FieldTypeDescription
fieldstringRequest field to inspect
operatorstringComparison operator
valuestringValue to compare against
case_sensitivebooleanEnable case-sensitive matching
negatedbooleanInvert the result

Example: OOB SQL Injection Campaign

This is a real detection chain from the bundled mnemos-oob-sqli-and-exfil.yaml rule file. It uses two regex trigger rules that detect individual OOB SQLi techniques, then a Mnemos correlation rule that links them into a campaign:

Step 1 — Trigger rules (regex)

# Trigger 1: OOB SQLi function primitives
- name: OOB-SQLi-Payload
  match_mode: regex
  severity: high
  action: block
  targets: [query, body, path]
  pattern: >-
    (?i)(?:load_file\s*\(|into\s+(?:out|dump)file\b|xp_cmdshell|
    xp_dirtree|utl_http\.request|dblink\s*\()

# Trigger 2: DNS/UNC exfil patterns
- name: OOB-SQLi-DNS-Exfil
  match_mode: regex
  severity: high
  action: block
  targets: [query, body]
  pattern: >-
    (?i)(?:\\\\\\\\[a-z0-9][-a-z0-9]*\.[a-z]{2,}\\\\|
    \.(?:burpcollaborator|oastify|interact\.sh)\b)

Step 2 — Mnemos correlation rule

- name: Mnemos - OOB SQLi Campaign
  match_mode: correlated
  severity: critical
  action: block
  tags: [mnemos, correlation, oob-sqli]
  correlation_config:
    window_seconds: 180
    threshold: 3
    group_by: source_ip
    trigger_rules:
      - OOB-SQLi-Payload
      - OOB-SQLi-DNS-Exfil
    sequence_mode: false
    unique_fields:
      - path
    predicates:
      - field: request.method
        operator: in_list
        value: GET,POST,PUT
      - field: request.path
        operator: matches_regex
        value: '(?i)(?:/api|/graphql|/query|/search|/admin|/v[0-9])'
This fires when the same client triggers both OOB-SQLi rules across 3+ unique paths within 3 minutes, targeting API-like endpoints. A single probing request is blocked by the trigger rules; the Mnemos rule escalates repeated probing to critical severity.

Example: Data Exfiltration Campaign

- name: Mnemos - Data Exfiltration Campaign
  match_mode: correlated
  severity: critical
  action: block
  tags: [mnemos, correlation, exfiltration]
  correlation_config:
    window_seconds: 300
    threshold: 3
    group_by: source_ip
    trigger_rules:
      - Exfil-Sensitive-Endpoint
      - Exfil-Bulk-Extraction
      - Exfil-Schema-Recon
    sequence_mode: false
    unique_fields:
      - path
    predicates:
      - field: request.method
        operator: in_list
        value: GET,POST
This correlates a client systematically walking sensitive endpoints (/api/users, /api/config, /api/billing/export) with bulk extraction parameters or schema reconnaissance within 5 minutes. The unique_fields: [path] constraint ensures the rule only fires when the client is walking different resources, not refreshing the same page.

Bidirectional Correlation (Response-Aware Rules)

Standard Mnemos rules correlate across requests — they evaluate what the client sends. Bidirectional correlation extends this to also evaluate what the server responds, enabling detection of attack patterns that are only visible in the full request-response flow.

Why Response Correlation Matters

Some attacks can only be detected by looking at both sides of the conversation:
  • Credential stuffing — the same client sends login requests, but only the response status codes (200 vs 401) reveal success/failure patterns
  • Forced browsing / IDOR — a client enumerates IDs, but only the response sizes or status codes reveal which resources exist
  • Data exfiltration — a client walks API endpoints, but the response Content-Type and body size reveal whether data was actually returned
  • Error-based reconnaissance — a client probes endpoints; 500 errors in the responses indicate the server is crashing on specific inputs

How It Works

Bidirectional correlation uses two separate correlation stores:
Request arrives
  |
  v
WAF rule chain evaluates (request-side)
  |
  v
Snapshot recorded to REQUEST correlation store
  |
  v
Request-side Mnemos rules evaluate
  |
  v
Request proxied to upstream
  |
  v
Response returns from upstream
  |
  v
Response fields captured (status, size, content-type, latency, headers, body sample)
  |
  v
Snapshot updated with response data, recorded to RESPONSE correlation store
  |
  v
Response-aware Mnemos rules evaluate
  |
  v
If match ──► retrospective block (auto-blacklist/timeout the source IP)
The WAF engine automatically routes correlation rules to the correct store based on their predicates:
  • Rules with only request-side predicates go to the request correlation store (evaluated immediately)
  • Rules with any response.* predicate go to the response correlation store (evaluated after the upstream responds)

Response Fields Available in Predicates

FieldDescription
response.statusHTTP status code (e.g., 200, 401, 500)
response.sizeResponse body size in bytes
response.content_typeResponse Content-Type header value
response.latency_msRequest-to-response latency in milliseconds
response.header.<name>Specific response header value
response.bodyResponse body sample (truncated)

Response-Aware Unique Fields

In addition to request-side unique fields, correlation rules can count unique values across response fields:
FieldDescription
response_statusUnique HTTP status codes
response_sizeUnique response body sizes
response_content_typeUnique Content-Type values

Example: Credential Stuffing Detection

- name: Mnemos - Credential Stuffing Campaign
  match_mode: correlated
  severity: critical
  action: block
  tags: [mnemos, correlation, credential-stuffing]
  correlation_config:
    window_seconds: 120
    threshold: 5
    group_by: source_ip
    unique_fields:
      - body
    predicates:
      - field: request.path
        operator: matches_regex
        value: '(?i)/(?:api/)?(?:auth|login|signin|token)'
      - field: response.status
        operator: equals
        value: "401"
This fires when the same client makes 5+ login attempts with different request bodies (different credentials) within 2 minutes, where all responses are 401 Unauthorized.

Example: Forced Browsing / IDOR Detection

- name: Mnemos - IDOR Enumeration
  match_mode: correlated
  severity: high
  action: block
  tags: [mnemos, correlation, idor]
  correlation_config:
    window_seconds: 60
    threshold: 10
    group_by: source_ip
    unique_fields:
      - path
    predicates:
      - field: request.path
        operator: matches_regex
        value: '(?i)/api/(?:users|accounts|orders|invoices)/\d+'
      - field: response.status
        operator: equals
        value: "200"
This detects a client walking sequential numeric IDs across 10+ unique paths within 1 minute where the server responds 200 — indicating the resources exist and were returned.

Retrospective Blocking

When a response-aware correlation rule fires, the response has already been sent to the client. Aegis cannot undo that response, but it can retrospectively block the source IP to prevent future requests:
  1. The response correlation match fires
  2. Aegis applies the same auto-blocking logic (blacklist or timeout, host or global scope)
  3. The source IP is blocked for all future requests
  4. The proxy runtime reloads immediately
This means the attacker may receive responses during the detection window, but is cut off as soon as the correlation threshold is met. The block reason is logged as a retrospective block with the correlation rule name and category.

Importing Mnemos Rules

Mnemos correlation rules can be imported alongside regular WAF rules via the same JSON/YAML import endpoint. The bundled mnemos-oob-sqli-and-exfil.yaml file is a complete example containing trigger rules and their corresponding Mnemos correlation rules in a single file.
POST /api/v1/rules/import
Content-Type: multipart/form-data
Imported correlation rules are validated through the same pipeline as UI-created rules — window_seconds, threshold, trigger_rules, unique_fields, and predicates are all checked server-side.

Correlation Events

When a Mnemos rule fires, a CorrelationEvent is persisted to SQLite with the matched snapshots. These events are queryable via the admin API and visible in the Mnemos page of the admin UI.

API

MethodPathDescription
GET/api/v1/correlation-eventsQuery correlation events (filterable by host, source IP, rule, time range)

Event Data

FieldDescription
idEvent ID
hostProxy host where the correlation fired
source_ipClient IP that triggered the correlation
rule_nameName of the Mnemos correlation rule
rule_idWAF rule ID
matched_snapshotsJSON array of the request snapshots that contributed to the match
window_secondsThe correlation window that was configured
thresholdThe threshold that was configured
created_atWhen the correlation event fired

Request Log Enrichment

When a request triggers a correlation match, the WAF detail in the request log is enriched with correlation context:
FieldDescription
correlation.window_secondsThe correlation window
correlation.thresholdThe configured threshold
correlation.matched_snapshotsSummary of contributing requests
This allows traffic log queries to surface which requests were part of a correlated campaign, not just which individual rule matched.

Admin UI

Mnemos has its own page in the Aegis admin dashboard accessible from the sidebar. The Mnemos page provides:
  • Live view of correlation events
  • Stateful request correlation history per client
  • Filtering by host, source IP, rule, and time range
In the rule editor, selecting match_mode: correlated switches to the correlation configuration interface where you define the window, threshold, trigger rules, predicates, and unique field constraints.

Tuning

ParameterEffect of increasingEffect of decreasing
window_secondsCatches slower campaignsReduces false positives from unrelated requests
thresholdFewer false positivesCatches faster / shorter campaigns
Trigger rulesMore specific detectionBroader detection with fewer prerequisites
unique_fieldsRequires diversity (different paths)Fires on repeated access to same resource
PredicatesNarrows to specific traffic patternsBroadens to all client traffic