Source overview
panther-labs/panther-analysis
Python-native Detection-as-Code for Panther — AWS, GCP, Azure, Okta, GitHub, endpoint.
panther-labs-panther-analysis
· Panther Python
· upstream repo ↗
· Apache 2.0
How detections work here
Panther detections are Python, not a rule DSL. Each detection is a .py file
defining a rule(event) function that returns a boolean, paired with a .yml
file carrying the metadata — ID, log types, severity, ATT&CK mapping, enabled
flag.
Panther streams normalized log events through these functions. Because the logic
is ordinary Python, it can do things a declarative rule cannot: look up
dictionaries, walk nested structures with event.deep_get(...), compute a
severity from the event's own contents. The same property means a Panther
detection cannot be mechanically translated to another SIEM — there is no query
to port.
How rules are written
Beyond rule(), a detection may define helper functions that Panther calls when
the rule returns true:
title(event)— the alert headline, usually interpolating event fields.severity(event)— overrides the static YAML severity per event.dedup(event)— returns a grouping key; events sharing it collapse into one alert rather than many.alert_context(event)— extra fields attached to the alert.
The YAML side declares LogTypes, Enabled, Severity, and ATT&CK under
Reports: MITRE ATT&CK: in TA0001:T1566 form — tactic and technique paired,
which is why this source's ATT&CK coverage is unusually complete.
What fires an alert
rule() returning True, subject to dedup() collapsing repeats. Severity is
whichever of the YAML value or the severity() function applies.
Content divides into four kinds, and they are not interchangeable: rule
(streaming detections, the bulk), policy (cloud resource misconfiguration
checks evaluated against state rather than events), scheduled_rule (queries
run on a timer), and correlation_rule (detections over other detections'
signals). Filter by content type on this page — a policy is a compliance
check, not a threat detection.
Reading a rule on this site
The Python body is shown as the rule's logic. Read rule() first; the helper
functions shape the alert, not the match.
Runbook from the YAML becomes triage notes on a rule's page. Because severity
can be computed at runtime by severity(), the severity shown here is the
static YAML declaration and may not be what a given event actually produces.
Gotchas
- A detection whose
rule()is triviallyreturn Trueis not broken — it is a passthrough for a source that has already done the detecting (a vendor alert feed), and the real work is intitle()andseverity(). Enabled: falsein the YAML means upstream ships it off by default. That flag does not map to our status field, so check it on the rule before assuming it runs.
Severity
- Critical 26
- High 288
- Medium 374
- Low 147
- Informational 189
Status
- Stable 883
- Experimental 141
Content types
Recently modified
all →| AWS RDS Instance Encryption | 2026-08-19 |
| SentinelOne Alert Passthrough | 2026-07-23 |
| AWS Console GetSigninToken Potential Abuse | 2026-07-07 |
| GreyNoise V3 Malicious IP Activity | 2026-07-06 |
| GTI/VirusTotal Threat Intelligence Indicator Match | 2026-07-06 |