Audit scenarios & playbook
A mapping of the questions internal and external auditors actually ask to Mergen detections — which built-in rule answers each or which custom-rule recipe to define, plus an honest list of what is out of scope. Every detection carries who (user, IP), what (rule, statement, tables/columns), and when.
Mergen records the what and the pattern; intent is a judgement the auditor makes from that evidence — though several patterns strongly imply it (exfiltration beaconing, privilege-escalation chains, credential-catalog reads). Mergen's job is to make the activity undeniable and searchable.
"Do you log DBA / privileged-user activity?"
Yes. A custom rule that records everything the named administrators do, at Info severity as a trail:
{
"id": "dba_activity",
"severity": "info",
"match": { "user_in": ["dba", "root", "postgres"] },
"message_template": "DBA activity: {kind} on {tables} by {user}"
} "Record everything that is NOT the application account." (the headline SoD ask)
List every legitimate service account in user_not_in; everything else — operators, scripts, third parties — is recorded:
{
"id": "non_app_access",
"severity": "warning",
"match": { "user_not_in": ["app_service"] },
"message_template": "non-app access: {kind} on {tables} by {user}"
} Verified by unit tests: sod_non_app_user_fires, sod_app_user_silent.
Writes to protected tables by non-app accounts
A read by an analyst is fine; a write to a financial table by a non-app account is Critical:
{
"id": "non_app_write",
"severity": "critical",
"match": {
"statement_kinds": ["Insert", "Update", "Delete"],
"tables_regex": "^(ledger|payments|payroll)$",
"user_not_in": ["app_service"]
}
} Verified by unit tests: non_app_write_fires_but_read_silent.
Scenario → rule coverage
| Privilege / role changes | role_privilege_escalation · dangerous_grant · role_impersonation | Built-in |
| Schema changes (DDL) | dangerous_ddl · ddl_by_non_admin | Built-in |
| Backdoors / persistence | security_definer_function · trigger_backdoor · dangerous_extension | Built-in |
| Bulk export | excessive_data_export | Built-in |
| File / direct exfiltration | exfil_direct | Built-in |
| PII / sensitive data (KVKK) | pii_content · turkish_pii · ozel_nitelikli_veri_access · sensitive_column_read | Built-in |
| Slow-drain / beaconing | exfil_byte_volume · exfil_time_pattern | Built-in |
| Off-hours activity | off_hours_query | Built-in |
| Behavioral deviation (UEBA) | ueba_anomaly · ueba_peer_anomaly | Built-in |
| Mass delete (no WHERE) | bulk_delete | Built-in |
| Audit/log tampering | audit_tamper | Built-in |
| Credential-catalog reads | system_catalog_recon | Built-in |
| Failed access / brute force | failed_login_burst · login_audit | Built-in |
| DBA activity trail | custom: user_in | Custom rule |
| Segregation of duties (non-app access) | custom: user_not_in | Custom rule |
| High-rate scraping | custom: rate | Custom rule |
Note: time is an optional axis — most rules run 24/7 (unwanted activity happens during business hours too). To bind a rule to time, add a time_window: e.g. "non-app access only after hours" as one Critical rule ({user_not_in} + {time_window start 18:00 end 08:00}). Use negate/days to restrict to business hours instead (UTC).
How to add a custom rule
- Rules → Custom rules → New. Pick the engine (pg/mongo) and severity.
- Set the match: statement kinds, table/column/command regex, user_in / user_not_in, require-no-WHERE — combine only what you need (AND semantics; an empty match matches everything).
- Optionally add a rate (count / window / group-by-user) for burst rules.
- Write a message template: {kind}, {tables}, {columns}, {user}.
- Save — the rule is pushed to agents on the next heartbeat (no restart) and can be scoped per host/group/global.
- Test — the panel previews against recently captured query patterns (approximate; exact matching runs live on the agent).
Out of current scope (honest gaps)
These stateful identity-anomaly scenarios are on the roadmap (advanced tier) and are NOT detected today — they should not be presented as covered:
- Account sharing (same credential, many hosts at once)
- Dormant-account reactivation
- Impossible travel (distant IPs in a short window)
- First-time-object access across the fleet