# Mothlight detection starter pack v1

Use current Mothlight observations to enrich and prioritize local detections. No rule performs unconditional IP blocking or account disablement. Begin in analyst review mode. Samples are synthetic documentation IPs, not observed infrastructure. v1 describes the normalized interchange schema; SIEM templates require field mapping and validation on your product version.

Start in [Console > Integrations](/account/integrations); see [API docs](/api-docs#integrations) for access. Indicator data remains subject to your API plan and license. Examples confer no redistribution rights.

## Inputs and schema

Fetch `/api/v1/feeds/edl?format=json&min_confidence=80` with the authentication configured in Console > Integrations. JSON has generated_at, window, criteria_version and entries. Use the JSON feed, not the newline IP-only feed: text drops the metadata required by these examples. Never put API keys or feed tokens in search definitions, source control or public URLs. Fetch with your organization's approved secret-aware collector; this pack makes no network requests.

Each entries row must have the following fields (see schema.json):

| Field | Meaning |
| --- | --- |
| ip | Canonical individual IPv4/IPv6 address; exact equality, no CIDR or ports |
| reason | Evidence summary treated as untrusted text, never executable code |
| confidence | Numeric observation confidence, 0–100; examples use >=80, not a probability of compromise |
| first_seen | UTC ISO 8601 start of observed activity |
| last_seen | UTC ISO 8601 latest observed activity |
| expires_at | UTC ISO 8601 expiry; strictly after last_seen, at most 24 hours later |

`GET /api/v1/lookup/ip/{ip}` can enrich a bounded set of local alert IPs with approved API-key access. Its response includes query, seen, verdict, confidence, reason, first_seen, last_seen, evidence and suggested_action, but **does not include expires_at**. For that alternative adapter, require seen=true and verdict=attacking, preserve canonical queried IP, map the six columns above, and set expires_at to the earlier of last_seen + 24 hours and collection time + 15 minutes. Discard expired results. Never use ASN aggregate lookups to invent IP rows. `not_seen` means unknown, never safe. API quotas still apply; respect Retry-After and avoid logging queried addresses or keys.

## Refresh and rollback

Collect every 15 minutes, validate the entire response, remove expired rows and atomically replace the snapshot; do not append indefinitely. Keep generated_at, refresh time, criteria_version, count and validation status in operational monitoring. Reject malformed/future timestamps. Alert if the last successful refresh is over 30 minutes old and pause enrichment while investigating. A failed fetch must not overwrite a good snapshot with an empty file; a validated successful empty response should clear it. Queries independently exclude expired rows. Normalize local IPv6 text to the same canonical representation before exact joins. Honor customer allowlists locally as well as server-side.

Convert a downloaded EDL JSON file offline (Python 3, standard library only):

```sh
python3 to-csv.py < edl.json > mothlight_ips.csv.tmp
# Only on successful validation, replace the deployed CSV atomically.
```

The converter emits only the six columns, checks expiry and deduplicates by rejecting duplicate IPs. On failure discard the temporary file; never deploy it. A valid empty feed produces a header-only CSV. For a reproducible sample, run `python3 to-csv.py --at 2026-11-03T12:00:00Z < sample-indicators.json`: three current rows remain; 203.0.113.30 is expired. Do not deploy sample IPs to enforcement systems. Save the previous validated configuration for rollback; disable enrichment searches or restore that configuration when troubleshooting, while continuing to honor expiry.

## Sigma

Download sigma/authentication-brute-force.yml and sigma/exploit-attempt.yml. These are experimental Sigma templates over **local alert records**, not raw logs. Implement a backend lookup join: canonical source.ip = indicator.ip, require current expiry, map reason/confidence/first_seen/last_seen/expires_at to mothlight.* fields, and set mothlight.match=true and mothlight.current=true only after successful validation. Missing or expired matches must set both booleans false. Never derive event.type from the feed reason.

Map event.kind=alert and event.type=authentication_brute_force from your existing repeated-authentication-failure detection (for example >=10 failures per IP in 15 minutes); map event.type=exploit_attempt from verified local exploit signature alerts. These custom normalized values are a pack contract, not built-in ECS event.type values. Use local backend field mappings before conversion. Sigma has no portable lookup join: importing the YAML alone does not create enrichment. Retain metadata in resulting alerts and review shared egress before escalation. [Sigma specification](https://sigmahq.io/sigma-specification/specification/sigma-rules-specification.html).

## Splunk

Install transforms.conf in your private app's local directory; deploy the converted CSV as lookups/mothlight_ips.csv. Map src_ip, event_kind and event_type to the normalized local alerts above, and choose your index. Run the two .spl searches interactively first. savedsearches.conf supplies disabled scheduled examples every 15 minutes over the previous 15 minutes, with no actions. Enable only after reviewing results and scheduler timing/deduplication. The scheduled search performs triage; your separate collector refreshes the CSV before it runs. No outbound call or key belongs in SPL. [Splunk lookup configuration](https://help.splunk.com/en/splunk-enterprise/administer/admin-manual/10.2/configuration-file-reference/10.2.0-configuration-file-reference/transforms.conf).

## Microsoft Sentinel

Convert EDL JSON to CSV, create a Watchlist alias mothlight_ips and choose ip as SearchKey. Your collector must replace/delete removed rows rather than merge stale entries; Watchlist's own refresh is not the indicator TTL. Import the six column names exactly. Run signinlogs.kql for >=10 failed sign-ins per IP in 15 minutes. In commonsecuritylog.kql replace LOCAL_VERIFIED_EXPLOIT_SIGNATURE with locally verified exploit signature IDs from your connector. These queries return candidate incidents for review only; do not attach blocking automation. [Microsoft Watchlist queries](https://learn.microsoft.com/en-us/azure/sentinel/watchlists-queries).

## Elastic

Create index mothlight-indicators-v1 using elastic/index.json as the request body for PUT /mothlight-indicators-v1. Load current JSON entries as documents (your collector supplies bulk action lines; sample-indicators.json is not a bulk request). Create PUT /_enrich/policy/mothlight_ips using enrich-policy.json, then POST /_enrich/policy/mothlight_ips/_execute. Replace/delete retired documents and execute the policy after each successful refresh; enrich policies are snapshots. Serialize refreshes to prevent overlapping replacement/execution. Use a staging index/alias switch for atomic production refreshes.

Map local alert fields as described under Sigma, including the pack's custom event.type values, then run enrichment.esql. Adapt logs-* to your indices. detection-rule.json is a disabled request body for POST /api/detection_engine/rules in Kibana, not an NDJSON import file; use the required kbn-xsrf header through approved tooling. It has no response actions. Validate field types and your installed ES|QL/detection API version before enabling. [Elastic ENRICH](https://www.elastic.co/docs/reference/query-languages/esql/commands/enrich), [ES|QL rules](https://www.elastic.co/docs/solutions/security/detect-and-alert/esql).

## Identity policy and safety

Follow [Entra and AD workflow](entra/README.md) for the separate format=entra password blocklist. IP evidence never justifies rejecting passwords or disabling users. Shared IPs, VPNs, proxies and reassigned addresses can belong to unrelated people. Expiry limits validity; absence is unknown, not safe. Retain your own evidence and use challenge/observe or human-approved, reversible responses according to policy. None of these examples proves compromise, actor identity or global reputation.
