---
title: "ThreatOps"
slug: threatops
category: security
term_status: ambiguous
evidence_status: verified
summary: "ThreatOps is an unstandardised label. This page uses it for running threat intelligence and threat hunting as one operation: priority intelligence requirements steer what is collected and analysed, and testable hypotheses steer hunts whose findings change defences."
audience: [CTI analysts, Threat hunters, SOC and detection leads, Security leaders, Beginners]
last_verified: 2026-10-17
key_takeaways:
  - "ThreatOps has no standard definition. Vendors use it for an intelligence-driven blocking service, a managed threat-hunting team and a gamified hunting-training programme. This page uses it for intelligence and hunting run as one operation."
  - "Start from a short list of priority intelligence requirements (PIRs), each answering one question for one decision. Intelligence nobody asked for is rarely acted on."
  - "IP addresses and hashes are cheap for an adversary to change; behaviours (TTPs) cost far more. Give indicators an expiry date and spend analyst time higher up the Pyramid of Pain."
  - "A hunt is a testable hypothesis with a scope and a time box. A hunt that finds nothing still succeeds if you are confident you would have seen the activity."
  - "Measure effects, not effort: detections created, gaps closed, PIRs answered and decisions changed, not reports written or indicators ingested."
  - "Share with TLP 2.0 labels over STIX 2.1 and TAXII 2.1, and check the legal basis where you operate. In the US, check the current sunset date of the Cybersecurity Information Sharing Act of 2015 protections before relying on them."
  - "Many organisations should consume intelligence and buy hunting rather than build both. An in-house programme is worth building only when telemetry, data retention and people who act on findings already exist."
related: [detectionops, soc-ops, responseops, vulnerabilityops, secops, secdataops, aiops-for-security, identityops]
---

## What ThreatOps is

### In 30 seconds

**ThreatOps**, as this page uses the word, is the operation that turns knowledge about adversaries into changed defences.
**Threat intelligence** answers questions decision-makers asked in advance, called priority intelligence requirements (PIRs).
**Threat hunting** tests written hypotheses against your own telemetry for activity that automated detection missed. Both feed
detection requests, patch priorities, incident escalations and briefs that change decisions.

NIST defines threat intelligence as "Threat information that has been aggregated, transformed, analyzed, interpreted, or enriched
to provide the necessary context for decision-making processes."[^nist-ti] Splunk's PEAK framework defines hunting as "any manual
or machine-assisted process intended to find security incidents missed by an organization’s automated detection systems."[^peak]
ThreatOps runs both as a service with requirements, owners, records and measures.

::: note The label is ambiguous
No standards body defines "ThreatOps" and vendors use it for different things (see
[What ThreatOps is not](#what-threatops-is-not)). The practices behind it, cyber threat intelligence (CTI) and threat hunting,
are established; this page marks its own boundaries as **editorial distinctions**.
:::

**Who this page is for.** Beginners, CTI analysts and hunters, SOC and detection leads who receive the outputs, and leaders
deciding whether to build, buy or skip.

### At a glance

| Aspect | Summary |
|---|---|
| Goal | Defences and decisions that change because of what is known about adversaries |
| Primary users | CTI analysts, threat hunters, SOC and detection leads, CISOs and risk owners |
| In scope | PIRs, source evaluation, analysis and reporting, IOCs versus TTPs, ATT&CK mapping, STIX/TAXII and threat intelligence platforms (TIPs), hunting, sharing through ISACs with TLP |
| Out of scope | Production detection engineering ([DetectionOps](../detectionops/)), alert triage ([SOC Ops](../soc-ops/)), incident handling ([ResponseOps](../responseops/)), vulnerability prioritisation ([VulnerabilityOps](../vulnerabilityops/)) |
| Prerequisites | Security telemetry you can query, retained long enough to look back; a team that can act on findings |
| Key outputs | PIR register, intelligence products, hunt records, detection requests, expiring indicator sets, shared reports |
| Term status | Ambiguous label over established practices |

### The problem it solves

Three failures recur without such an operation.

**Intelligence without a customer.** Teams subscribe to feeds and forward news. FIRST's CTI SIG (special interest group) says PIRs exist to provide
decision-quality information "versus simply ‘reporting the news’".[^first-pir] Without requirements, nobody can say which feed or
report was worth its cost.

**Indicators treated as intelligence.** An IP address or file hash is cheap for the adversary to replace. In David Bianco's
Pyramid of Pain, "the amount of pain you cause an adversary depends on the types of indicators you are able to make use
of".[^pyramid] Some adversaries leave few indicators at all. In the
2024 joint advisory on Volt Typhoon, CISA, NSA, FBI and partners wrote that "Conventional IOCs associated with the malicious
activity are generally lacking", and reported indications of footholds kept "for at least five years".[^volt]

**Waiting for alerts.** Mandiant's M-Trends 2026, based on its own investigations, reports:
"Global median dwell time rose to 14 days from 11 days", and a median of 122 days for cyber-espionage and North Korean IT-worker
incidents.[^mtrends] Those figures describe Mandiant's caseload, not every organisation, but they explain proactive search. NIST SP 800-53 Rev. 5 offers hunting as an optional control (RA-10): a capability to "Search for indicators of
compromise in organizational systems" and to "Detect, track, and disrupt threats that evade existing controls".[^sp80053]

| Without ThreatOps | With ThreatOps |
|---|---|
| Feeds pushed straight into blocking, never expired | Indicators rated, labelled, alert-only by default, expiring |
| Hunting is "searching around" when someone has time | Hunts are written hypotheses with scope, time box and record |
| Findings end in a chat thread | Findings become detection requests, gap tickets or incidents |

### What ThreatOps is not

**The name.** The NIST CSRC glossary returns no results for "threatops".[^nist-gl] Vendors use it in at least three senses:

1. **An intelligence-driven blocking service.** Centripetal (2022) defines ThreatOps as "the process of operationalizing threat
   intelligence to shield against all known and emerging attacks", combining automatic blocking with human hunters.[^centripetal]
2. **A managed-hunting team brand.** A marketplace listing for Huntress's managed detection and response (MDR) service calls its
   human threat hunters "The Huntress ThreatOps team".[^huntress]
3. **A gamified hunting-training programme.** SentinelOne's ThreatOps (2020–2026) is an "industrial-scale gamified platform" for
   hunting practice, run by its solutions engineers and also used in sales evaluations.[^s1]

The spaced phrase "threat operations" is a separate case: platform vendors use it loosely, as in ThreatQuotient's "We believe
the foundation of threat operations is people."[^threatq] None of these is a community standard, so this page classifies the
label as **ambiguous** and adopts one reading.

::: decision Editorial distinction used across the Atlas
ThreatOps produces **requirements, intelligence and validated hunt findings**. It does not own production detections, alert
triage, incident handling or patch decisions. The handoff "a validated hunt finding becomes a detection request" is this Atlas's
boundary with [DetectionOps](../detectionops/), not an industry standard.
:::

**What else it is not.**

- **Not a feed subscription.** Feeds are raw collection; FIRST's early-stage guidance uses them for "flagging/alerting but not
  automated blocking".[^first-stage1]
- **Not threat modelling.** Modelling an application's design belongs to [DevSecOps](../devsecops/); ThreatOps feeds it
  adversary knowledge.
- **Not the SOC.** Triage and 24×7 monitoring belong to [SOC Ops](../soc-ops/); a hunter escalates and does not run the incident.

## Where it comes from and where it sits

### Origins and evolution

The vocabulary comes from government intelligence; the cyber practice formed through public papers and standards:

| Year | Milestone |
|---|---|
| 2011 | Hutchins, Cloppert and Amin, *Intelligence-Driven Computer Network Defense*: the intrusion kill chain; atomic, computed and behavioural indicators[^killchain] |
| 2013 | Diamond Model of Intrusion Analysis (adversary, infrastructure, capability, victim)[^diamond]; Bianco's Pyramid of Pain[^pyramid] |
| 2015 | Sqrrl hunting reference model and Hunting Maturity Model (HMM)[^peak][^peak-metrics] |
| 2016, 2018 | NIST SP 800-150 on cyber threat information sharing;[^sp800150] CSF 1.1 outcome ID.RA-2: CTI "is received from information sharing forums and sources"[^csf11] |
| 2018 | TaHiTI hunting methodology, Dutch Payments Association (as described by Bianco)[^peak] |
| 2021 | STIX 2.1 and TAXII 2.1 approved as OASIS Standards[^stix21][^taxii21] |
| 2022 | TLP 2.0 authoritative from August 2022[^tlp] |
| 2023 | PEAK hunting framework (Splunk SURGe)[^peak] |
| 2024 | NIST CSF 2.0 keeps it as ID.RA-02 and adds DE.AE-07: CTI integrated into the analysis of adverse events[^csf2] |
| 2026 | CTI-CMM 1.3 (January); ATT&CK v20 (13 October)[^cticmm][^attack-updates] |

### Glossary and mental model

| Term | Meaning on this page | Example |
|---|---|---|
| PIR | Priority intelligence requirement. FIRST's criteria: "ask only one question", focus on "a specific fact, event, or activity", support "a single decision"[^first-mh] | "Is any group exploiting our VPN product family this quarter?" |
| Strategic, operational, tactical intelligence | Audience levels: leaders; security managers; analysts and tools. FIRST adds "technical" at the bottom[^first-stage3] | Board brief; hunt plan; watchlist |
| IOC | Indicator of compromise: an observable such as an IP, domain or hash | `203.0.113.50` seen in a phishing wave |
| TTP | Tactics, techniques and procedures: how an adversary operates | Flooding a user with MFA prompts |
| Pyramid of Pain | Indicator types ordered by how much it costs the adversary when you deny them[^pyramid] | Hashes at the bottom, TTPs at the top |
| MITRE ATT&CK | A knowledge base of adversary tactics and techniques "based on real-world observations"[^attack-stix] | T1621 MFA Request Generation |
| STIX 2.1 / TAXII 2.1 | OASIS standards: a JSON language for CTI, and an HTTPS API to exchange it[^stix21][^taxii21] | An Indicator object served from a TAXII Collection |
| TIP | Threat intelligence platform: stores, scores, links and distributes intelligence | MISP, OpenCTI |
| TLP | Traffic Light Protocol 2.0 labels: TLP:RED (named recipients only), TLP:AMBER (recipient's organisation and clients, need to know; TLP:AMBER+STRICT = the organisation only), TLP:GREEN (the community), TLP:CLEAR (no limit)[^tlp] | TLP:AMBER+STRICT |
| Hunt (hypothesis-driven) | A testable supposition checked against data; PEAK describes it with ABLE: Actor, Behavior, Location, Evidence[^peak-hypo] | "A crew is pushing MFA prompts at finance staff" |
| Baseline hunt | Learn what normal looks like, then examine deviations[^peak] | Rare parent–child process pairs |
| Retro-hunt (sweep) | Search past data for newly published indicators | Advisory hashes over 90 days of endpoint data |
| ISAC | Information Sharing and Analysis Center, usually sector-based[^isacs] | A financial-sector ISAC |
| Diamond Model | An intrusion event has four linked features (adversary, infrastructure, capability, victim); analysts pivot from one to the others[^diamond] | Malware → its command-and-control (C2) domain and IP → other hosts calling that IP |
| RFI | Request for information: a one-off question outside the PIR register | "Is this phishing kit linked to a known crew?" |
| Data acronyms | SIEM: security information and event management; EDR: endpoint detection and response; IdP: identity provider; ASN: autonomous system number (an IP's network); OSINT: open-source intelligence | Lab 2 |

**Mental model: two loops and a pyramid.** The intelligence loop decides *what matters*; the hunt loop checks *whether it is
happening here*; the pyramid decides *how durable the defence will be*.

### How ThreatOps relates to other Ops

The Atlas divides security operations by the flow of work; [SecOps](../secops/) is the hub.

::: figure Where ThreatOps sits in the security-operations flow
```mermaid
flowchart TB
  SD["SecDataOps: telemetry"]
  TO["ThreatOps: requirements,<br/>intel, hunts"]
  DO["DetectionOps:<br/>detections"]
  VO["VulnerabilityOps"]
  SOC["SOC Ops: triage"]
  RO["ResponseOps:<br/>incidents"]
  SD -->|"data for hunts"| TO
  TO -->|"detection request"| DO
  TO -->|"exploitation intel"| VO
  DO -->|"alerts"| SOC
  TO -->|"live finding"| RO
  RO -.->|"lessons, IOCs"| TO
  SOC -.->|"patterns"| TO
  VO ~~~ RO
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029
  class TO core
  class SD,DO,VO,SOC,RO neutral
```
Text equivalent: SecDataOps supplies telemetry to ThreatOps. ThreatOps sends detection requests to DetectionOps, exploitation
intelligence to VulnerabilityOps and live findings to ResponseOps; DetectionOps alerts go to SOC Ops. Dotted feedback edges:
ResponseOps returns lessons and new indicators, SOC Ops returns recurring patterns that become hunt topics.
:::

| Neighbour | ThreatOps owns | The neighbour owns |
|---|---|---|
| [DetectionOps](../detectionops/) | PIRs, hypotheses, hunt findings, the detection request | Writing, testing, deploying and tuning production detections |
| [SOC Ops](../soc-ops/) | Proactive search without an alert | Alert queues, triage, shifts and SLAs |
| [ResponseOps](../responseops/) | Scoping hunts and intelligence during incidents | Containment, eradication, evidence, notification |
| [VulnerabilityOps](../vulnerabilityops/) | Exploitation intelligence for your estate | Prioritising and tracking fixes (CISA's KEV catalogue of exploited CVEs, EPSS exploit-probability scores, SLAs) |
| [SecDataOps](../secdataops/) | Stating which data the hunts need | Collecting, parsing and retaining it |

## Principles and operating model

### A proposed charter and principles

No official ThreatOps manifesto exists; this charter is **this Atlas's proposal**.

**Mission.** Reduce adversaries' time and room in our environment by deciding what to look for, looking, and turning what we
learn into defences that run without us.

**Principles.**

1. **Requirements first.** Every product and hunt traces to a PIR or a named stakeholder's question. FIRST: PIRs "are not infinite,
   they must be limited and well-scoped to key decision points"; "Less is more."[^first-pir]
2. **Climb the pyramid.** Use atomic indicators quickly and let them expire; invest analyst time in behaviours.[^pyramid]
3. **Hypotheses are testable and time-boxed.** A hunt states what would prove or disprove it, where, and in which data.[^peak-hypo]
4. **Every hunt ends in an artefact:** a detection request, gap ticket, escalation, or a record that the activity would have
   been visible.[^peak-detect]
5. **Say how sure you are.** Each judgement carries a probability word and a confidence level, as FIRST recommends.[^first-wep]
6. **Share by default within the label.** Use TLP; remove personal data the recipient does not need.
7. **Automation for volume, people for judgement.** Assessments, PIR changes, attribution and blocking have a named human owner.
   Anyone on call may remove a blocking indicator at once and must record it; the CTI lead reviews within an hour.

**Non-goals.** Building a library of every actor; running production detections; operating the incident; buying every feed.

### Building blocks

| Block | Minimum viable form |
|---|---|
| PIR register | A reviewed table of 5–8 PIRs with owners and review dates |
| Collection plan | A source list with A–F and 1–6 ratings[^first-source] |
| Knowledge store | A TIP (MISP, OpenCTI) or, early on, a version-controlled repository |
| Analytic standard | Probability word plus confidence; assumptions listed; peer review for products leaving the team |
| Hunt programme | One recorded hunt a fortnight |
| Dissemination paths | Brief for leaders, ticket for engineers, STIX/TAXII for tools |
| Sharing agreements | ISAC membership, TLP policy, legal sign-off |

**Analytic rigour.** Analysts tend to settle on the first explanation that fits. The US government's tradecraft primer
counters this with structured techniques: a *key assumptions check* lists what a judgement rests on; *analysis of competing
hypotheses* (ACH) tests each piece of evidence against every plausible explanation, aiming to disprove rather than
confirm.[^cia-sat] Use ACH for contested judgements such as attribution; evidence that fits every hypothesis decides nothing.

### Roles, ownership and RACI

Small organisations combine these roles; in an early programme FIRST calls the CTI analyst role "typically a secondary
duty".[^first-stage1] One accountable owner per activity is what matters.

| Activity | CTI lead | Analyst or hunter | Detection engineering | SOC or IR lead | CISO, risk owners |
|---|---|---|---|---|---|
| Set and review PIRs | R | C | I | C | A |
| Rate sources, manage feeds | A | R | I | I | I |
| Write intelligence products | A | R | I | C | I |
| Run a hunt | A | R | C | I | I |
| Escalate live malicious activity | I | R | I | A | I |
| Build the production detection | C | C | A/R | C | I |
| Allow a feed to auto-block | C | C | R | C | A |
| Share outside the organisation | A | R | I | C | I |

R = responsible, A = accountable, C = consulted, I = informed. Legal and privacy (not shown) are consulted on PIRs, source terms
and every external share.

### Lifecycle: the intelligence loop and the hunt loop

FIRST's CTI SIG settled on a six-step cycle: "Direction, Collection, Processing, Analysis, Dissemination, Feedback
(Review)".[^first-methods] PEAK structures each hunt as Prepare, Execute and Act, with knowledge feeding every phase.[^peak]

::: figure The intelligence loop and the hunt loop
```mermaid
flowchart TB
  D1["Direction: PIRs"] --> C1["Collection"]
  C1 --> P1["Processing"]
  P1 --> A1["Analysis"]
  A1 --> S1["Dissemination"]
  S1 --> F1["Feedback"]
  F1 -->|"revise PIRs"| D1
  A1 -->|"hunt topics"| H1["Hunt loop (PEAK):<br/>topic and hypothesis"]
  H1 --> H2["Prepare: scope, data"]
  H2 --> H3["Execute: analyse"]
  H3 --> H4["Act: record, hand off"]
  H4 -->|"internal intel"| C1
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
  class D1,C1,P1,A1,S1,F1 core
  class H1,H2,H3,H4 decision
```
Text equivalent: The intelligence loop runs Direction (PIRs), Collection, Processing, Analysis, Dissemination and Feedback,
which revises the PIRs. Analysis sends hunt topics into the hunt loop (orange nodes, PEAK): topic and hypothesis, Prepare (scope, data),
Execute (analyse) and Act (record, hand off), which returns internal intelligence to Collection.
:::

**Day 0, 1 and 2.** Day 0 agrees PIRs, data access and sharing rules; Day 1 delivers first products and hunts; Day 2 is reviews
([Operating model and governance](#operating-model-and-governance)), expiry and measurement ([Metrics and KPIs](#metrics-and-kpis)).

### Operating model and governance

| Cadence | Forum | Inputs | Decisions |
|---|---|---|---|
| Daily (15 min) | Intelligence triage | New advisories, ISAC posts, RFIs | Retro-hunt or not; owner |
| Weekly | Hunt planning | Backlog, PIR gaps, incidents, data gaps | Next hunts and time boxes |
| Monthly | Outputs review with detection and SOC leads | Detection requests, gaps, feed precision | Detection priorities; feeds to drop |
| Quarterly | PIR review with stakeholders | Feedback, threat changes, metrics | Retire, add or rewrite PIRs; budget |

FIRST's PIR guidance quotes the line "If PIRs don’t change, you’re fighting the plan and not the enemy".[^first-pir]
**Requests for information.** Stakeholders also send one-off RFIs; CTI-CMM treats them as an input to detection engineering
and an output of hunting.[^cticmm] Log each (see [Templates](#templates)); a recurring RFI is a PIR candidate.

**Escalation rule:** a hunter who sees likely malicious activity escalates at once to the incident process (PEAK's "Escalate
Critical Findings" step) and keeps hunting only with the incident lead's agreement.[^peak-hypo] **Incident scoping.** During an
incident, [ResponseOps](../responseops/) asks ThreatOps to find every foothold and to hunt again until a cycle finds nothing
new; the incident lead sets priorities, and queries and results are evidence.

## Architecture and workflow

### Reference architecture

A ThreatOps architecture is mostly data handling with two trust boundaries: untrusted intelligence in, sensitive intelligence
out.

::: figure Reference architecture: from sources to defences and back out
```mermaid
flowchart LR
  subgraph IN["External, untrusted"]
    direction TB
    S1["ISAC and<br/>gov feeds"]
    S2["Commercial<br/>intel"]
    S3["Advisories,<br/>OSINT"]
  end
  S4["Internal:<br/>incidents, hunts"]
  TIP["TIP: rate,<br/>expire, label"]
  subgraph OUT["Consumers"]
    direction TB
    O1["SIEM, EDR<br/>watchlists"]
    O2["Hunt backlog"]
    O3["VulnerabilityOps"]
    O4["Leadership<br/>briefs"]
  end
  GATE["Sharing gate<br/>to partners"]
  S1 --> TIP
  S2 --> TIP
  S3 --> TIP
  S4 --> TIP
  TIP --> O1
  TIP --> O2
  TIP --> O3
  TIP --> O4
  TIP --> GATE
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  classDef risk fill:#fbeceb,stroke:#b4332b,color:#122029
  classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029
  class TIP core
  class GATE risk
  class S1,S2,S3,S4,O1,O2,O3,O4 neutral
```
Text equivalent: Three external, untrusted sources (ISAC and government feeds, commercial intelligence, advisories and open
sources) and one internal source (own incidents and hunts) flow into a threat intelligence platform that rates, expires and
labels them. It feeds SIEM and EDR watchlists, the hunt backlog, VulnerabilityOps and leadership briefs. Anything leaving the
organisation passes a sharing gate on its way to partners.
:::

| Component | Design choice and trade-off |
|---|---|
| Inbound connectors | Prefer TAXII 2.1 where offered; CISA's AIS, for example, expects a TAXII 2.1 client[^ais] |
| Watchlists | Alert-only by default; blocking only for feeds with measured precision |
| Sharing gate | Enforces TLP, strips unneeded personal data, records approvals; slower beats unrecorded |

**Alternatives.** A small team can start with a version-controlled repository instead of a TIP; for bought hunting, see
[When to use](#when-to-use-and-when-not-to-use).

### End-to-end workflow

::: figure From trigger to closed hunt, with exception paths
```mermaid
flowchart TB
  T["Trigger: advisory, PIR<br/>or incident lesson"] --> Q1{"Relevant<br/>to a PIR?"}
  Q1 -->|"no"| L["Log, close,<br/>review PIRs"]
  Q1 -->|"yes"| R["Retro-hunt any indicators,<br/>set expiry"]
  R --> H["Write hypothesis<br/>(ABLE)"]
  H --> Q2{"Data<br/>available?"}
  Q2 -->|"no"| G["Gap ticket<br/>to SecDataOps"]
  Q2 -->|"yes"| X["Hunt within<br/>time box"]
  B["Baseline hunt:<br/>new data source<br/>a PIR needs"] --> X
  X --> Q3{"Malicious<br/>activity?"}
  Q3 -->|"no"| Q4{"Would we have<br/>seen it?"}
  Q3 -->|"yes"| E["Escalate to<br/>ResponseOps"]
  Q4 -->|"no"| G
  Q4 -->|"yes"| DR["Detection request<br/>to DetectionOps"]
  E --> DR
  DR --> REC["Record hunt,<br/>update PIR"]
  G --> REC
  classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
  classDef risk fill:#fbeceb,stroke:#b4332b,color:#122029
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  class Q1,Q2,Q3,Q4 decision
  class E,G risk
  class T,B,R,H,X,DR,REC,L core
```
Text equivalent: A trigger (advisory, PIR or incident lesson) that matches no PIR is logged and closed, and the PIRs reviewed.
A matching trigger leads to a retro-hunt of any indicators it supplies, with expiry dates, then an ABLE hypothesis. Without
data, a gap ticket goes to SecDataOps; otherwise the hunt runs in its time box. A new data source
a PIR needs enters there as a baseline hunt, with no hypothesis. Malicious activity is escalated to ResponseOps and yields
a detection request. If nothing is found: would it have been visible? No means a gap ticket; yes means a detection
request to DetectionOps. Every path ends with the hunt recorded and the PIR updated.
:::

**Acceptance criteria for "done".** The record states hypothesis, data and time range searched, queries, verdict and
artefacts, so a reviewer who was not on the hunt can rerun it.

## Practices, frameworks and tools

### Core practices and playbooks

| Practice | Trigger | Owner | Done when |
|---|---|---|---|
| Write and review PIRs | Quarterly; major change | CTI lead with stakeholders | One question, decision, owner and review date each |
| Rate sources | New feed or contact; quarterly | Analyst | Every source has an A–F rating and a use note |
| Handle indicators | Indicator received | Analyst, automated in the TIP | No active atomic indicator without an expiry date |
| Retro-hunt | Credible advisory matching a PIR | Hunter | Searched window stated; hits escalated |
| Hypothesis hunt | Backlog item | Hunter | Verdict plus at least one artefact |
| Baseline hunt | New data source[^peak-baseline] | Hunter | Normal described well enough to define "abnormal" |
| Write a product | PIR due, significant event | Analyst; peer reviewer | Decision owner confirms it answers the PIR |
| Share | Finding useful to peers | Analyst; approver | Approval recorded; personal data checked |

**Three details that are easy to get wrong.**

- **Source evaluation.** FIRST recommends rating source reliability from A ("Reliable") to E, with F for "Cannot be judged", and
  the information from 1 ("Confirmed") to 5, with 6 for "Cannot be judged". Its example rates a trusted provider's new
  experimental feed "A3": good source, untested information.[^first-source]
- **Indicator lifecycle.** STIX makes `valid_until` optional, and without it "there is no constraint on the latest time for
  which the Indicator is valid".[^stix21] Set it yourself: short for IPs, longer for domains, longest for behavioural detections,
  and record why.
- **Estimative language.** FIRST recommends the NATO Words of Estimative Probability (WEP; for example "Likely" for 60–90%) and
  confidence levels (High, Moderate, Low), used for each judgement "but not in the same sentence".[^first-wep]

::: figure The Pyramid of Pain as a handling policy
```mermaid
flowchart TB
  P6["TTPs: hunt and detect behaviour"]
  P5["Tools: detect tool use, share analysis"]
  P4["Host and network artifacts: hunt"]
  P3["Domains: alert, expire in weeks"]
  P2["IP addresses: alert, expire in days"]
  P1["Hash values: match; block only via the policy gate"]
  P6 --- P5
  P5 --- P4
  P4 --- P3
  P3 --- P2
  P2 --- P1
  P1 ~~~ L["Legend: teal = analyst time;<br/>grey = automated, expiring;<br/>higher = costlier for the adversary"]
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029
  classDef legend fill:#ffffff,stroke:#c9d6da,color:#122029
  class P6,P5,P4 core
  class P3,P2,P1 neutral
  class L legend
```
Text equivalent: Bianco's six levels, top to bottom, with suggested handling: TTPs (hunt and detect behaviour), tools (detect
tool use, share analysis), host and network artifacts (hunt), domains (alert, expire in weeks), IP addresses (alert, expire in
days), hash values (match; block only through the policy gate below). Higher levels cost the adversary more to change. Teal
levels get analyst time; grey levels are automated and expire. The handling is this Atlas's suggestion, not Bianco's.
:::

### Methods, standards and frameworks

| Name | Kind | What it gives ThreatOps |
|---|---|---|
| NIST SP 800-53 Rev. 5 RA-10, PM-16, PM-16(1), RA-3(3) | Optional: RA-10 and RA-3(3) are in no SP 800-53B baseline; PM-16 and PM-16(1) are organisation-level programme controls[^sp80053b] | Hunting; a threat awareness programme with "a cross-organization information-sharing capability"; automated sharing[^sp80053] |
| NIST CSF 2.0 ID.RA-02, DE.AE-07 | Framework outcomes | Receiving CTI; integrating it into the analysis of adverse events[^csf2] |
| NIS2 Article 29 | EU law (through national transposition) | Voluntary exchange of IOCs, "adversarial tactics, threat-actor-specific information" within communities[^nis2] |
| STIX 2.1, TAXII 2.1 | OASIS Standards (2021) | Exchange format and API[^stix21][^taxii21] |
| TLP 2.0 | FIRST standard (2022) | Sharing labels[^tlp] |
| MITRE ATT&CK v20 | Knowledge base | Shared vocabulary for behaviour; 15 Enterprise tactics and 227 techniques (October 2026)[^attack-updates] |
| Kill chain, Diamond Model, Pyramid of Pain | Analytic models | Phases, pivots and indicator value[^killchain][^diamond][^pyramid] |
| PEAK; Sqrrl model; TaHiTI | Hunting frameworks | Hunt types, phases, deliverables[^peak] |
| FIRST CTI curriculum; CTI-CMM | Practitioner guidance and maturity model | PIRs, source ratings, uncertainty language; stakeholder-based maturity[^first-pir][^cticmm] |

ATT&CK's FAQ says "Tactics are unordered and may not all occur in a single intrusion", unlike the kill chain's ordered
phases.[^attack-faq] And the catalogue changes: v20 lists "Stealth" (TA0005) and a separate "Defense Impairment" tactic
(TA0112), so coverage maps that say "Defense Evasion" need re-mapping.[^attack-tactics]

### Tooling landscape

Choose by job, not brand; checked October 2026.

| Job | Representative options | Strengths | Watch-outs |
|---|---|---|---|
| Store, correlate and share intelligence | MISP (open source; 2.5.x, October 2026; security releases are frequent, so track the release feed)[^misp-home] | Correlation, sightings, ATT&CK galaxies, sharing groups, STIX import and export, REST API[^misp] | Community sync needs governance |
| Model knowledge as a graph | OpenCTI (Filigran): Community Edition under Apache 2.0, Enterprise Edition under a separate licence[^opencti] | Knowledge schema based on STIX 2; connectors to MISP and ATT&CK | Check which features are Enterprise-only |
| Government and sector sharing | CISA AIS (no cost; TAXII 2.1)[^ais]; ISACs[^isacs] | Sector-relevant, often early | Eligibility, terms of use, sharing obligations |
| Behaviour catalogue | ATT&CK STIX data and TAXII server[^attack-stix][^attack-taxii] | Machine-readable, versioned | The public TAXII server allows 50 requests per 10 minutes per IP |
| Hunt data and analysis | Your SIEM, EDR, data lake, notebooks | Where the evidence is | Retention and field quality decide what a hunt can prove |

**Selection criteria.** Expiry, confidence and TLP per object; lossless STIX 2.1 import and export; scriptability; who maintains it
when the champion leaves. Keep PIRs and hunt records in a format you own.

### Automation and AI

Automate the volume work: pulling feeds, de-duplication, enrichment, expiry and watchlist updates. In FIRST's mature stage,
repeatable processes are heavily automated and people work "from TTPs level and above".[^first-stage3] Language models can
draft summaries, extract indicators and suggest ATT&CK mappings; treat their output as an unrated source, check it against the
original, and never let a model assign confidence or TLP.
Evaluating and governing such tools is covered in [AIOps for Security](../aiops-for-security/).

## ThreatOps in practice

### Reference implementation

For an illustrative mid-size company (one CTI analyst, one part-time hunter, a SIEM, EDR and an IdP), two artefacts carry most
of the design: the PIR register and the indicator policy.

_Example status: YAML syntax-checked by the Atlas validator; not executed (these are configuration records, not programs)._

```yaml
# pir-register.yaml - one question, one decision, one owner per PIR (illustrative)
version: 2026-Q4
review_by: 2027-01-15
pirs:
  - id: PIR-01
    question: >-
      Is any intrusion set exploiting remote-access products we expose
      (VPN, virtual desktops) against organisations in our sector this quarter?
    decision: Emergency patching or isolation of exposed remote-access services
    decision_owner: Head of Infrastructure
    level: operational
    sources: [SECTOR-ISAC, CISA-AIS, VENDOR-ADVISORIES, OWN-EDGE-LOGS]
    outputs: [retro-hunt, exploitation intel to VulnerabilityOps, brief]
    review: monthly
  - id: PIR-02
    question: >-
      Are identity-focused extortion crews targeting our help desk or MFA,
      and would our current telemetry show it?
    decision: Help-desk identity verification and MFA method policy
    decision_owner: CISO
    level: operational
    sources: [SECTOR-ISAC, ATTACK-V20, IDP-LOGS, HELPDESK-TICKETS]
    outputs: [hypothesis hunts, detection requests, gap tickets]
    review: quarterly
  - id: PIR-03
    question: >-
      Which threat developments in the next 12 months should change our
      security investment plan?
    decision: Annual security budget allocation
    decision_owner: Executive risk committee
    level: strategic
    sources: [SECTOR-ISAC, VENDOR-ANNUAL-REPORTS, GOVERNMENT-ADVISORIES]
    outputs: [semi-annual strategic brief]
    review: semi-annual
```

```yaml
# indicator-policy.yaml - local defaults; tune with measured precision (illustrative)
default_action: alert            # blocking is the exception, not the default
expiry_days:                     # sets STIX valid_until when the source gave none
  ipv4-addr: 14
  domain-name: 60
  url: 30
  file-hash-sha256: 365
block_allowed_when:
  source_reliability_in: [A, B]
  information_credibility_in: [1, 2]
  feed_precision_90d_min: 0.9    # confirmed-malicious hits / investigated hits
  not_on_allowlists: [cdn-ranges, cloud-provider-ranges, partner-ranges]
unlabelled_inbound_treated_as: TLP:AMBER   # local policy, not part of TLP
revert:                          # a blocking feed is a production control
  allowed_by: anyone-on-call     # remove the indicator first, ask later
  record: [who, when, indicator, feed, reason]
  reviewed_by: cti-lead
  review_within_hours: 1
review:
  stale_indicator_report: weekly
  owner: cti-lead
```

The blocking rule follows FIRST's staging: early programmes alert rather than block; later ones may block from automatic feeds
"if appropriate", and "Careful consideration is required".[^first-stage1][^first-stage2] The gate covers every type, hashes
included: a feed can list a legitimate admin tool. The 0.9 threshold and expiry periods are illustrative; set yours from your
own hit data.

### Hands-on labs

The labs need only a laptop, cost nothing and touch no production system. All were executed on 2026-10-16 and again on
2026-10-17 (Python 3.8.10, SQLite 3.31.1), except the optional TAXII step of Lab 3.

#### Lab 1 (beginner): turn a PIR into a ranked hunt backlog with ATT&CK data

**Objective:** rank the techniques that PIR-02's intrusion sets are publicly known to use, so the first hunts target shared
behaviour. **Prerequisites:** Python 3.8 or later, internet access, about 60 MB of disk and 300 MB of memory (peak measured:
280 MB). **Cost and risk:** none.

1. Download the Enterprise ATT&CK v20.0 bundle (STIX 2.1) from MITRE's repository (commands below).[^attack-stix] The pinned file
   keeps the output reproducible; the unversioned `enterprise-attack.json` always holds the latest release.
2. Save the script below as `hunt_backlog.py`.
3. Run it with the ATT&CK group IDs for Scattered Spider (G1015), LAPSUS$ (G1004) and Akira (G1024).
4. Replace the IDs with the groups your own PIR names, and keep the output with the PIR record.

```bash
BASE=https://raw.githubusercontent.com/mitre-attack/attack-stix-data/master
curl -L -o enterprise-attack-20.0.json \
  "$BASE/enterprise-attack/enterprise-attack-20.0.json"
python3 hunt_backlog.py enterprise-attack-20.0.json G1015 G1004 G1024
```

_Example status: executed on 2026-10-16 and 2026-10-17 against ATT&CK v20.0 (bundle modified 2026-10-13)._

```python
"""Rank ATT&CK techniques by how many priority groups use them.

Usage: python3 hunt_backlog.py enterprise-attack-20.0.json G1015 G1004 G1024
"""
import json
import sys
from collections import defaultdict


def attack_id(obj):
    for ref in obj.get("external_references", []):
        if ref.get("source_name") == "mitre-attack":
            return ref.get("external_id")
    return None


def active(obj):
    return not obj.get("revoked") and not obj.get("x_mitre_deprecated")


def main(path, group_ids):
    with open(path, encoding="utf-8") as fh:
        objects = json.load(fh)["objects"]
    by_id = {o["id"]: o for o in objects}
    version = next(o["x_mitre_version"] for o in objects
                   if o["type"] == "x-mitre-collection")
    groups = {o["id"]: o for o in objects
              if o["type"] == "intrusion-set" and active(o)
              and attack_id(o) in group_ids}
    missing = set(group_ids) - {attack_id(g) for g in groups.values()}
    if missing:
        sys.exit(f"Unknown or deprecated group IDs: {sorted(missing)}")

    users = defaultdict(set)  # technique STIX id -> group names
    for rel in objects:
        if (rel["type"] == "relationship" and active(rel)
                and rel["relationship_type"] == "uses"
                and rel["source_ref"] in groups
                and rel["target_ref"].startswith("attack-pattern--")):
            tech = by_id.get(rel["target_ref"])
            if tech and active(tech):
                users[tech["id"]].add(groups[rel["source_ref"]]["name"])

    rows = []
    for tid, names in users.items():
        tech = by_id[tid]
        tactics = sorted(p["phase_name"] for p in tech.get("kill_chain_phases", []))
        rows.append((len(names), attack_id(tech), tech["name"], tactics))
    rows.sort(key=lambda r: (-r[0], r[1]))

    print(f"ATT&CK Enterprise v{version}; groups: "
          + ", ".join(sorted(g["name"] for g in groups.values())))
    print(f"{len(rows)} distinct techniques; "
          f"{sum(1 for r in rows if r[0] == len(groups))} used by all groups")
    for count, tid, name, tactics in rows[:12]:
        more = f" +{len(tactics) - 1}" if len(tactics) > 1 else ""
        print(f"{count}/{len(groups)}  {tid:<10} {name[:38]:<38} {tactics[0]}{more}")


if __name__ == "__main__":
    if len(sys.argv) < 3:
        sys.exit(__doc__)
    main(sys.argv[1], set(sys.argv[2:]))
```

**Expected output** (verified by execution; counts change with each ATT&CK release):

```text
ATT&CK Enterprise v20.0; groups: Akira, LAPSUS$, Scattered Spider
92 distinct techniques; 2 used by all groups
3/3  T1078      Valid Accounts                         initial-access +3
3/3  T1133      External Remote Services               initial-access +1
2/3  T1003.003  NTDS                                   credential-access
2/3  T1018      Remote System Discovery                discovery
2/3  T1021.001  Remote Desktop Protocol                lateral-movement
2/3  T1059.001  PowerShell                             execution
2/3  T1068      Exploitation for Privilege Escalation  privilege-escalation
2/3  T1069.002  Domain Groups                          discovery
2/3  T1078.004  Cloud Accounts                         initial-access +3
2/3  T1087.002  Domain Account                         discovery
2/3  T1090      Proxy                                  command-and-control
2/3  T1098.003  Additional Cloud Roles                 persistence +1
```

`+3` means three more tactics. **Validation:** open T1133 on attack.mitre.org; its procedure examples include all three
groups. **Limits:** only direct group links count, not links through software or campaigns: T1098.005 Device Registration
(Lab 2) reaches Scattered Spider only through campaign C0027, so it is missing here.[^attack-t1098] **Troubleshooting:** "Unknown or deprecated group
IDs" (exit code 1) means a typo or a revoked group. **Teardown:** delete the files.

#### Lab 2 (intermediate): run a hypothesis-driven hunt on sign-in logs

**Objective:** test a written hypothesis, then act on the result. **Prerequisites:** Python 3 with its built-in `sqlite3`; the
synthetic file below (documentation IP ranges, invented users). **Cost and risk:** none; never copy real sign-in logs to a
laptop without approval.

**Hypothesis, in PEAK's ABLE form**:[^peak-hypo] *Actor:* identity-focused extortion crews (PIR-02). *Behavior:* MFA push
flooding (ATT&CK T1621) until the user approves, then registering a new MFA method (T1098.005 Device Registration). *Location:*
the workforce IdP. *Evidence:* IdP sign-in and audit events: a burst of `mfa_denied`, then `success` from a network (ASN) new for
that user, then `mfa_method_added` within an hour. PEAK advises hunting "one or two pieces" of behaviour at a time, not a whole
attack chain;[^peak-hypo] this hypothesis chains exactly two.

1. Save the data as `signins.csv` and the script as `hunt_mfa.py`.
2. Run `python3 hunt_mfa.py signins.csv`.
3. Run again with `--min-denials 1` and explain the extra row.
4. Act: write a detection request for the HIGH pattern (template in [Templates](#templates)) and a reset-and-verify task for the
   LEAD.

```text
ts,user,event,src_ip,asn
2026-10-01T08:02:00Z,amara,success,198.51.100.10,64500
2026-10-01T08:05:00Z,li,success,198.51.100.11,64500
2026-10-02T08:01:00Z,amara,success,198.51.100.10,64500
2026-10-02T09:15:00Z,jonas,success,198.51.100.12,64500
2026-10-03T08:03:00Z,li,success,198.51.100.11,64500
2026-10-14T02:10:00Z,li,mfa_denied,203.0.113.50,64511
2026-10-14T02:11:00Z,li,mfa_denied,203.0.113.50,64511
2026-10-14T02:13:00Z,li,mfa_denied,203.0.113.50,64511
2026-10-14T02:16:00Z,li,mfa_denied,203.0.113.50,64511
2026-10-14T02:19:00Z,li,success,203.0.113.50,64511
2026-10-14T02:24:00Z,li,mfa_method_added,203.0.113.50,64511
2026-10-14T07:58:00Z,amara,mfa_denied,198.51.100.10,64500
2026-10-14T07:59:00Z,amara,success,198.51.100.10,64500
2026-10-15T11:00:00Z,jonas,mfa_denied,192.0.2.77,64499
2026-10-15T11:01:00Z,jonas,mfa_denied,192.0.2.77,64499
2026-10-15T11:02:00Z,jonas,mfa_denied,192.0.2.77,64499
2026-10-15T11:30:00Z,jonas,success,198.51.100.12,64500
```

_Example status: executed on 2026-10-16 with the synthetic data above._

```python
"""Hunt: MFA flooding (T1621), sign-in from a new network, new MFA method (T1098.005).

Usage: python3 hunt_mfa.py signins.csv [--min-denials 3] [--window-min 15]
"""
import argparse
import csv
import sqlite3

QUERY = """
WITH bursts AS (
  SELECT d.user, MAX(d.ts) AS last_denial, COUNT(*) AS denials, d.asn
  FROM ev d
  WHERE d.event = 'mfa_denied'
  GROUP BY d.user, d.asn, strftime('%Y-%m-%dT%H', d.ts)
  HAVING COUNT(*) >= :min_denials
     AND (julianday(MAX(d.ts)) - julianday(MIN(d.ts))) * 1440 <= :window
)
SELECT b.user, b.denials, s.ts AS success_ts, s.src_ip, s.asn,
       NOT EXISTS (SELECT 1 FROM ev h
                   WHERE h.user = b.user AND h.event = 'success'
                     AND h.asn = s.asn AND h.ts < b.last_denial) AS new_asn,
       EXISTS (SELECT 1 FROM ev m
               WHERE m.user = b.user AND m.event = 'mfa_method_added'
                 AND m.ts BETWEEN s.ts
                     AND strftime('%Y-%m-%dT%H:%M:%SZ', s.ts, '+60 minutes'))
         AS method_added
FROM bursts b
JOIN ev s ON s.user = b.user AND s.event = 'success' AND s.asn = b.asn
 AND s.ts > b.last_denial
 AND s.ts <= strftime('%Y-%m-%dT%H:%M:%SZ', b.last_denial, '+30 minutes')
ORDER BY s.ts;
"""

# Bursts with no later success from that network: someone else may hold the password.
UNANSWERED = """
WITH bursts AS (
  SELECT user, asn, MAX(ts) AS last_denial, COUNT(*) AS denials
  FROM ev WHERE event = 'mfa_denied'
  GROUP BY user, asn, strftime('%Y-%m-%dT%H', ts)
  HAVING COUNT(*) >= :min_denials
     AND (julianday(MAX(ts)) - julianday(MIN(ts))) * 1440 <= :window
)
SELECT b.user, b.denials, b.last_denial, b.asn FROM bursts b
WHERE NOT EXISTS (SELECT 1 FROM ev s WHERE s.user = b.user AND s.event = 'success'
                  AND s.asn = b.asn AND s.ts > b.last_denial)
ORDER BY b.last_denial;
"""


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("csv_path")
    ap.add_argument("--min-denials", type=int, default=3)
    ap.add_argument("--window-min", type=int, default=15)
    args = ap.parse_args()
    db = sqlite3.connect(":memory:")
    db.execute("CREATE TABLE ev (ts TEXT, user TEXT, event TEXT, src_ip TEXT, asn TEXT)")
    with open(args.csv_path, newline="", encoding="utf-8") as fh:
        rows = [(r["ts"], r["user"], r["event"], r["src_ip"], r["asn"])
                for r in csv.DictReader(fh)]
    db.executemany("INSERT INTO ev VALUES (?, ?, ?, ?, ?)", rows)
    params = {"min_denials": args.min_denials, "window": args.window_min}
    hits = db.execute(QUERY, params).fetchall()
    print(f"{len(rows)} events loaded; {len(hits)} candidate(s)")
    for user, denials, ts, ip, asn, new_asn, added in hits:
        rating = "HIGH" if new_asn and added else "MEDIUM" if new_asn else "LOW"
        print(f"{rating:<6} user={user} denials={denials} success={ts} asn={asn} "
              f"new_net={bool(new_asn)} new_mfa={bool(added)}")
    for user, denials, last, asn in db.execute(UNANSWERED, params):
        print(f"LEAD   user={user} denials={denials} last={last} asn={asn} "
              "(password likely known)")


if __name__ == "__main__":
    main()
```

**Expected output** (verified by execution):

```text
17 events loaded; 1 candidate(s)
HIGH   user=li denials=4 success=2026-10-14T02:19:00Z asn=64511 new_net=True new_mfa=True
LEAD   user=jonas denials=3 last=2026-10-15T11:02:00Z asn=64499 (password likely known)
```

With `--min-denials 1` a third row appears, `LOW user=amara denials=1 …`: one denied prompt, then a normal sign-in from her usual
network, the noise a production rule must not alert on.

**Validation:** the HIGH row matches the hypothesis. The LEAD row is a finding the hypothesis did not predict: `jonas` denied three
pushes from an unfamiliar network. If your IdP sends a push only after a correct password (check this), someone else probably
knows it. **Carrying it to production:** the KQL sketch below runs the same logic on Microsoft Entra ID sign-in and audit
logs.[^entra-signin][^entra-500121][^entra-mfa][^entra-audit][^entra-audit-ref] Other IdPs log equivalents. **Troubleshooting:** bursts are grouped by clock hour, so one spanning an hour boundary splits; production logic uses
sliding windows. **Limits:** flooding from one network and signing in from another is missed by design. **Teardown:** delete
the files.

_Example status: KQL sketch, not executed; names checked against Microsoft's documentation on 2026-10-17; check one
`TargetResources` record's layout before trusting the last join._

```kusto
// Lab 2 hypothesis on Microsoft Entra ID logs in a Log Analytics workspace. Not executed.
// SigninLogs.ResultType: "0" = success; "500121" = "User didn't complete the MFA prompt"
// (denial reasons include "user declined the authentication"). 500121 also "often
// appears if the user hasn't completed setting up MFA": users still registering can
// match all three signals, so exclude onboarding accounts before alerting.
// AuditLogs.OperationName "User registered security info" = an MFA method was added.
let bursts = SigninLogs
  | where TimeGenerated > ago(30d) and ResultType == "500121"
  | summarize denials = count(), first_denial = min(TimeGenerated),
              last_denial = max(TimeGenerated)
      by UserPrincipalName, AutonomousSystemNumber, bin(TimeGenerated, 1h)
  | where denials >= 3 and last_denial - first_denial <= 15m;
let successes = SigninLogs
  | where TimeGenerated > ago(90d) and ResultType == "0"
  | project UserPrincipalName, AutonomousSystemNumber, IPAddress,
            success_ts = TimeGenerated;
let first_seen = successes
  | summarize first_success = min(success_ts)
      by UserPrincipalName, AutonomousSystemNumber;
let methods_added = AuditLogs
  | where OperationName in ("User registered security info",
                            "User registered all required security info")
  | extend UserPrincipalName = tostring(TargetResources[0].userPrincipalName)
  | project UserPrincipalName, method_added = TimeGenerated;
bursts
| join kind=inner successes on UserPrincipalName, AutonomousSystemNumber
| where success_ts between (last_denial .. last_denial + 30m)
| join kind=inner first_seen on UserPrincipalName, AutonomousSystemNumber
| extend new_net = first_success > first_denial   // no earlier success from this ASN
| join kind=leftouter methods_added on UserPrincipalName
| extend added = method_added between (success_ts .. success_ts + 60m)
| summarize mfa_adds = countif(added)
    by UserPrincipalName, denials, success_ts, IPAddress, AutonomousSystemNumber, new_net
| extend new_mfa = mfa_adds > 0
| order by success_ts asc
```

A real precedent for the third signal: FireEye's chief executive told US House committees in 2021 that the company found its
intrusion after "a peculiar alert indicating that one of our employee’s accounts had registered a second phone" for
two-factor codes; the employee had not.[^mandia] An alert, not a hunt, but the signal works when its benign rate is known and
the check (ask the user) is cheap.

#### Lab 3 (intermediate): package a finding for sharing and read from a TAXII server

**Objective:** express the Lab 2 finding as a STIX 2.1 bundle labelled with TLP 2.0, check it before sharing, and optionally
query a public TAXII 2.1 server. **Prerequisites:** Python 3; `curl`. **Risk:** sharing real data needs the approval described in
[Quality, security, privacy and compliance](#quality-security-privacy-and-compliance).

**Why TLP 2.0 needs an extension.** STIX 2.1 defines markings for the older TLP labels only: "Other instances of tlp-marking
MUST NOT be used or created".[^stix21] TLP 2.0 labels use an extension from the OASIS CTI committee's common-objects
repository; the bundle uses its TLP:GREEN object.[^tlp2-stix] It shares the IP (short `valid_until`) and links it by STIX ID to
the two behaviours, T1621 and T1098.005, which the receiver resolves against its own ATT&CK copy.
Its `confidence` of 70 is STIX's value for Admiralty credibility 2, "Probably True" (Appendix A), the same 1–6 scale FIRST
uses to rate information.[^stix21] **Side effect:** `created_by_ref` plus a Sighting whose `where_sighted_refs` names your
own identity tells every recipient that your organisation was targeted; anonymise or omit them when that matters.

1. Save the bundle as `finding.json` and the checker as `check_bundle.py`; run `python3 check_bundle.py finding.json`.
2. Delete the `valid_until` line from the indicator and run again; the check must fail.
3. Optional: list the collections on MITRE's ATT&CK TAXII 2.1 server (command below).[^attack-taxii] It may refuse requests
   (rate limit, HTTP 503); the offline equivalent is the Lab 1 bundle.

```bash
curl -H 'Accept: application/taxii+json;version=2.1' \
  https://attack-taxii.mitre.org/api/v21/collections/
```

_Example status: JSON syntax-checked; both checks executed on 2026-10-16 and 2026-10-17; the bundle was not sent anywhere._

```json
{
  "type": "bundle",
  "id": "bundle--2ec35eb0-cc59-4fef-8af4-b6f947df006a",
  "objects": [
    {
      "type": "marking-definition",
      "spec_version": "2.1",
      "id": "marking-definition--bab4a63c-aed9-4cf5-a766-dfca5abac2bb",
      "created": "2022-10-01T00:00:00.000Z",
      "name": "TLP:GREEN",
      "extensions": {
        "extension-definition--60a3c5c5-0d10-413e-aab3-9e08dde9e88d": {
          "extension_type": "property-extension",
          "tlp_2_0": "green"
        }
      }
    },
    {
      "type": "identity",
      "spec_version": "2.1",
      "id": "identity--8fbe50f4-ab4f-4990-aa78-f4d363562898",
      "created": "2026-10-16T10:00:00.000Z",
      "modified": "2026-10-16T10:00:00.000Z",
      "name": "Example Corp CTI team",
      "identity_class": "organization"
    },
    {
      "type": "indicator",
      "spec_version": "2.1",
      "id": "indicator--2382283f-9d2e-4e23-82f1-8296bd9ad321",
      "created_by_ref": "identity--8fbe50f4-ab4f-4990-aa78-f4d363562898",
      "created": "2026-10-16T10:00:00.000Z",
      "modified": "2026-10-16T10:00:00.000Z",
      "name": "Source of MFA push flood against a workforce IdP",
      "description": "Seen once; low durability. Prefer the behaviour (T1621).",
      "indicator_types": ["malicious-activity"],
      "pattern": "[ipv4-addr:value = '203.0.113.50']",
      "pattern_type": "stix",
      "valid_from": "2026-10-14T02:10:00Z",
      "valid_until": "2026-10-28T02:10:00Z",
      "confidence": 70,
      "object_marking_refs": [
        "marking-definition--bab4a63c-aed9-4cf5-a766-dfca5abac2bb"
      ]
    },
    {
      "type": "relationship",
      "spec_version": "2.1",
      "id": "relationship--f9bc48c8-ca32-4c85-bcfe-ae59ed839bd6",
      "created": "2026-10-16T10:00:00.000Z",
      "modified": "2026-10-16T10:00:00.000Z",
      "relationship_type": "indicates",
      "source_ref": "indicator--2382283f-9d2e-4e23-82f1-8296bd9ad321",
      "target_ref": "attack-pattern--954a1639-f2d6-407d-aef3-4917622ca493",
      "object_marking_refs": [
        "marking-definition--bab4a63c-aed9-4cf5-a766-dfca5abac2bb"
      ]
    },
    {
      "type": "relationship",
      "spec_version": "2.1",
      "id": "relationship--3d0b8c52-1f7e-4c1a-9a55-6b2f0e9c7d41",
      "created": "2026-10-16T10:00:00.000Z",
      "modified": "2026-10-16T10:00:00.000Z",
      "relationship_type": "indicates",
      "source_ref": "indicator--2382283f-9d2e-4e23-82f1-8296bd9ad321",
      "target_ref": "attack-pattern--7decb26c-715c-40cf-b7e0-026f7d7cc215",
      "object_marking_refs": [
        "marking-definition--bab4a63c-aed9-4cf5-a766-dfca5abac2bb"
      ]
    },
    {
      "type": "sighting",
      "spec_version": "2.1",
      "id": "sighting--6753e044-c34e-4297-a036-644cc381c0f8",
      "created_by_ref": "identity--8fbe50f4-ab4f-4990-aa78-f4d363562898",
      "created": "2026-10-16T10:00:00.000Z",
      "modified": "2026-10-16T10:00:00.000Z",
      "first_seen": "2026-10-14T02:10:00Z",
      "last_seen": "2026-10-14T02:24:00Z",
      "count": 1,
      "sighting_of_ref": "indicator--2382283f-9d2e-4e23-82f1-8296bd9ad321",
      "where_sighted_refs": ["identity--8fbe50f4-ab4f-4990-aa78-f4d363562898"],
      "object_marking_refs": [
        "marking-definition--bab4a63c-aed9-4cf5-a766-dfca5abac2bb"
      ]
    }
  ]
}
```

```python
"""Minimal pre-share checks for a STIX 2.1 bundle (not a full validator)."""
import json
import sys

REQUIRED = {
    "indicator": ["pattern", "pattern_type", "valid_from"],
    "relationship": ["relationship_type", "source_ref", "target_ref"],
    "sighting": ["sighting_of_ref"],
}
TLP2_EXT = "extension-definition--60a3c5c5-0d10-413e-aab3-9e08dde9e88d"

bundle = json.load(open(sys.argv[1], encoding="utf-8"))
ids = {o["id"] for o in bundle["objects"]}
problems = []
for obj in bundle["objects"]:
    for prop in REQUIRED.get(obj["type"], []):
        if prop not in obj:
            problems.append(f"{obj['id']}: missing {prop}")
    if obj["type"] not in ("marking-definition", "identity"):
        refs = obj.get("object_marking_refs", [])
        if not any(r in ids for r in refs):
            problems.append(f"{obj['id']}: no TLP marking in bundle")
    if obj["type"] == "marking-definition" and TLP2_EXT not in obj.get("extensions", {}):
        problems.append(f"{obj['id']}: not a TLP 2.0 marking")
    if obj["type"] == "indicator" and "valid_until" not in obj:
        problems.append(f"{obj['id']}: atomic indicator without valid_until")
external = sorted({o.get("target_ref") for o in bundle["objects"]
                   if o.get("target_ref") and o["target_ref"] not in ids})
print(f"{len(bundle['objects'])} objects; {len(problems)} problem(s)")
for p in problems:
    print("PROBLEM", p)
for ref in external:
    print("EXTERNAL", ref, "(resolve against ATT&CK)")
sys.exit(1 if problems else 0)
```

**Expected output** (verified by execution). Step 1:

```text
6 objects; 0 problem(s)
EXTERNAL attack-pattern--7decb26c-715c-40cf-b7e0-026f7d7cc215 (resolve against ATT&CK)
EXTERNAL attack-pattern--954a1639-f2d6-407d-aef3-4917622ca493 (resolve against ATT&CK)
```

Step 2 prints `PROBLEM indicator--2382283f-…: atomic indicator without valid_until` and exits with code 1. Step 3 (dated
observations, not expected output): one request on 2026-10-16 returned HTTP 200 with three collections; later requests on
2026-10-16 and 2026-10-17 returned HTTP 503. **Troubleshooting:** MITRE rate-limits the
server, suggests the bundles for heavier use and requires a valid `Accept` header.[^attack-taxii] **Validation:** before any
real share, a second person checks the TLP label, personal data and approval record. **Teardown:** delete the files.

### Use cases and scenarios

Case 1 is sourced; cases 2–4 are illustrative.

**1. Living off the land (sourced).** The February 2024 Volt Typhoon advisory listed indicators and linked a TLP:CLEAR STIX
file from the accompanying malware analysis report. It warned that many
organisations lack the baselines needed for "behavior analytics, anomaly detection, and proactive hunting".[^volt]
*Illustrative response:* a utility retro-hunts the STIX indicators, then writes baseline hunts for admin tools used from unusual
hosts. **Pitfall:** declaring "not affected" after an IOC sweep alone.

**2. Identity-led extortion (illustrative).** M-Trends 2026 reports voice phishing as the second most common initial
infection vector (11%) in Mandiant's investigations.[^mtrends] A retailer's CISO sets PIR-02; Lab 1 ranks the shared techniques and
Lab 2 tests the MFA-flooding hypothesis. The hunt finds no intrusion but shows that help-desk tickets do not record the requester's
verified identity: a gap ticket and a process change for [IdentityOps](../identityops/). **Success:** the MFA detection in
production. **Pitfall:** reading ATT&CK group data as a forecast.

**3. Exploitation intelligence for patching (illustrative).** An ISAC post (TLP:AMBER) reports exploitation of a VPN appliance
before a patch exists. ThreatOps confirms the exposure, retro-hunts the indicators, and hands
[VulnerabilityOps](../vulnerabilityops/) a dated note: "exploited in our sector; we run 3 exposed units". VulnerabilityOps owns
priority and deadline; [PatchOps](../patchops/) owns the rollout. **Pitfall:** forwarding the post to a supplier outside the
organisation's clients, which TLP:AMBER does not allow.

**4. Strategic brief (illustrative).** For PIR-03 the brief follows the [template](#templates): a bottom line with a probability
word, confidence in a separate sentence, one recommendation. **Success:** the risk committee funds a specific control.
**Pitfall:** actor names and no recommendation.

## Measuring, securing and paying for it

### Metrics and KPIs

The CTI-CMM authors observe that "most organizations develop metrics that measure level of effort or throughput" rather than
impact;[^cticmm] PEAK says the same of hunting: count "twelve new automated detections", not "nine hunts".[^peak-metrics] The
set below is **this Atlas's proposal**, built on PEAK's measures and CTI-CMM's example metrics.

| KPI | Formula | Data source | Pitfall |
|---|---|---|---|
| PIR coverage | PIRs with at least one product or hunt in the period ÷ active PIRs | PIR register, product log | Easy to game with thin products |
| Intelligence-to-action rate | Products followed by a recorded decision or change ÷ products disseminated | Product log, stakeholder feedback | Needs consumers to record actions |
| Hunt conversion rate | Hunts producing at least one detection created or updated ÷ hunts completed | Hunt records, detection repository | Rewards easy hunts; read with the next KPI |
| Gap closure rate | Gaps closed ÷ gaps reported (data, visibility, misconfiguration) | Gap tickets | Other teams close them; track age |
| Indicator hygiene | Active atomic indicators with an expiry ÷ active atomic indicators | TIP | Absurd periods defeat it |
| Feed precision | Confirmed-malicious hits ÷ investigated hits, per feed, 90 days | Watchlist hits, triage outcomes | Small samples; shared hosting inflates false hits |

Review indicator hygiene weekly; hunt conversion, gap closure and feed precision monthly; the rest quarterly.

**Worked calculation (illustrative quarter).** PIR coverage: 5 of 6 PIRs had a product or hunt, 5 ÷ 6 = 83%. Intelligence-to-action:
14 of 40 products led to a recorded action, 35%. Hunt conversion: 5 of 12 hunts created or updated a detection, 42%. Gap closure:
4 of 9, 44%. Feed precision: 18 confirmed of 120 investigated hits, 15%. **Reading:** coverage is healthy; most products change
nothing, so ask consumers why and cut unused ones; hunting improves detection; the feed, far below the 0.9 threshold, stays
alert-only and is a cancellation candidate.

**Vanity metrics.** Indicators ingested, reports published, hunts started and "ATT&CK coverage" percentages. PEAK warns that "not
everything in ATT&CK is intended to be turned into a detection".[^peak-metrics]

### Quality, security, privacy and compliance

- **Analytic quality.** Use FIRST's source ratings and uncertainty language, check key assumptions, and peer-review every product
  that leaves the team.
- **Operational security.** FIRST advises discussing any interaction with underground sources with company lawyers.[^first-source]
  Use dedicated, non-attributable infrastructure for adversary-facing research.
- **Sharing labels.** TLP labels (see the glossary) tell recipients how far they may share, but "TLP is not a formal
  classification scheme": binding terms come from your sharing agreement, and the source may add restrictions.[^tlp]
- **Personal data.** Indicators can contain personal data (email addresses, user names, IPs). Share only what the recipient
  needs; data-protection law varies by jurisdiction (see [PrivacyOps](../privacyops/)).
- **Legal basis for sharing.** NIS2 Article 29 has EU Member States enable voluntary sharing within communities and require
  essential and important entities to notify their competent authority when joining or leaving one; details depend on national
  transposition.[^nis2] In the US, the Congressional Research Service summarises the Cybersecurity Information Sharing
  Act of 2015 as giving antitrust and liability protections for authorised sharing and requiring personal information to be
  removed; its provisions run to **11 December 2026** (CRS, 3 September 2026), so check their status.[^crs] Involve
  [LegalOps](../legalops/) before the first external share.
- **Evidence.** A hunt that becomes an incident follows [ResponseOps](../responseops/) evidence rules from then on.

### Cost, capacity and sustainability

The main cost drivers are people, data retention and paid intelligence. **Retention** can be the hidden one: a retro-hunt looks
back only as far as telemetry is kept, the long-dwell cases in [The problem it solves](#the-problem-it-solves) exceed 90 days,
and a retention increase fills forward (see [the judgement call](#a-judgement-call-a-second-feed-or-a-hunter)). Price retention per
data source with [SecDataOps](../secdataops/) and keep longer only the sources your PIRs need. **Feeds** should be renewed on
measured precision and on how often they answered a PIR. **People:** the illustrative plan assumes a part-time hunter finishes
a hunt a fortnight; when data must first be gathered and cleaned (PEAK's "Gather Data" and "Pre-Process Data" steps), that
pace drops, so data quality is a capacity lever.[^peak-hypo]

### Assurance of the operating model

Quarterly, sample five hunt records and rerun one; check that escalations reached [ResponseOps](../responseops/) and detection
requests reached [DetectionOps](../detectionops/); list expired indicators still on watchlists; ask each PIR owner whether the
last product changed a decision. Risk signals: a PIR register unchanged for two quarters, no data-gap tickets (nobody checks
visibility), and blocking rules whose source nobody can name.

## When things go wrong

### Common failures and troubleshooting

| Symptom | Likely cause | Diagnosis | Remediation |
|---|---|---|---|
| Products not read | No PIR; wrong audience | Ask three consumers what they did with the last one | Bottom line plus recommendation; retire unused ones |
| Watchlist alerts mostly benign | Old or shared-infrastructure IOCs | Hit age and hosting type per feed | Expire, allowlist, demote the feed |
| Hunts produce nothing | Vague hypotheses or missing data | Read the last five hunt records | Rewrite in ABLE form; raise gap tickets |
| Findings sit unbuilt | No detection-engineering intake | Age of open detection requests | Intake SLA with [DetectionOps](../detectionops/) |
| Sharing stalls | Unclear approval, fear of liability | Time from request to approval | Pre-approved sharing classes |

#### Worked runbook: a feed indicator blocks a shared IP (illustrative)

*Situation.* At 09:10 the checkout page fails for some customers. Firewall logs show denies from a rule fed by a commercial
indicator list; the blocked address belongs to a content-delivery network (CDN) that served a malicious domain weeks ago.

1. **Contain (on-call engineer, minutes).** Remove the indicator from the block list; charter principle 7 and the policy's
   `revert` block pre-authorise this without the CTI lead. Record who, when, which indicator and why.
2. **Stop recurrence (CTI lead, within the hour).** Switch the feed to alert-only; check its other indicators for shared hosting.
3. **Diagnose.** Record source rating, first-seen date, `valid_until` (none was set) and the feed's 90-day precision; check the
   CDN allowlist (not maintained).
4. **Recover and communicate.** Confirm recovery with the service owner; report through [IncidentOps](../incidentops/) as an
   availability incident caused by a security control.
5. **Prevent.** Enforce expiry on import, refresh allowlists from providers' published ranges, apply the precision gate, put
   blocking feeds under change control, and track "blocks reverted" monthly.

### Anti-patterns and myths

- **"More feeds, more protection."** Every feed adds triage load and false blocks; measure precision before adding another.
- **Attribution theatre.** Attribute only when the name changes a defence, a response or a legal step.
- **The heat-map goal.** A green ATT&CK matrix measures mapping effort, not protection; the tactics are not even a
  sequence.[^attack-faq]
- **Hunting as SOC overflow.** Hunters on the alert queue means no hunting; fix [SOC Ops](../soc-ops/) capacity.
- **Myth: sharing is risky, so share nothing.** TLP labels, pre-approved sharing classes and legal frameworks such as NIS2
  Article 29 exist to make sharing manageable.[^tlp][^nis2]

## Deciding and adopting

### When to use and when not to use

**Build it when** you have queryable telemetry with history, people who act on findings, stakeholders willing to set PIRs, and a
reason to search proactively: a targeted sector, a selected control such as RA-10, or intrusions found late in the past.

**Do not build it yet when** the basics are missing: without endpoint or identity telemetry a hunter has nothing to search; with
an unhandled alert queue, findings join the backlog. FIRST notes "it may be best to stay in stage 1 and outsource more advanced
activities".[^first-stages] Alternatives: your sector's ISAC, government advisories, and managed hunting whose findings come back
to you. A bought service must include response to what it finds, or a named internal owner for its findings, plus a route
for its detection requests and gap tickets into your teams; otherwise bought findings stall like in-house ones.
**Hidden responsibilities:** legal review of sharing, retention costs, the detection work hunts create, and stakeholder
time for PIRs.

### Decision framework

::: figure Should we build, buy, go lean or fix data first?
```mermaid
flowchart TB
  Q1{"Telemetry kept<br/>90+ days?"}
  Q1 -->|"no"| A1["Fix data first;<br/>meanwhile triage advisories,<br/>hunt recent data"]
  Q1 -->|"yes"| Q2{"Owner for<br/>findings?"}
  Q2 -->|"no"| A2["Buy hunting with<br/>response included;<br/>name a findings owner"]
  Q2 -->|"yes"| Q3{"Stakeholders<br/>set PIRs?"}
  Q3 -->|"no"| A3["Lean: advisories,<br/>retro-hunts, ISAC"]
  Q3 -->|"yes"| Q4{"Targeted, or<br/>hunting required?"}
  Q4 -->|"no"| A3
  Q4 -->|"yes"| A4["Build: PIRs, TIP,<br/>hunt programme"]
  A1 ~~~ Q2
  A2 ~~~ Q3
  A3 ~~~ Q4
  classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
  classDef risk fill:#fbeceb,stroke:#b4332b,color:#122029
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  class Q1,Q2,Q3,Q4 decision
  class A1,A2 risk
  class A3,A4 core
```
Text equivalent: four questions down the left, exits to the right. Telemetry kept 90 days or more? If not, fix data first
with SecDataOps and meanwhile triage advisories and hunt recent data (the "wait" exit). Someone owns acting on findings? If not,
buy hunting that includes response, keep intelligence alert-only and name an internal owner for findings. Stakeholders will set
PIRs? If not, run lean: advisories, retro-hunts, ISAC. Targeted sector, or hunting required by contract or a selected control?
If not, stay lean; if yes, build PIRs, a TIP and a hunt programme. The 90-day threshold is illustrative.
:::

### Maturity model

This is **the Atlas's model**, not an official one, aligned with FIRST's three stages,[^first-stages] the Hunting Maturity Model
(HMM0–HMM4) as PEAK presents it,[^peak-metrics] and CTI-CMM levels CTI0 (Pre-Foundational) to CTI3 (Leading).[^cticmm]
Thresholds are proposals.

| Level | Observable behaviour | Exit criteria | Roughly aligns with |
|---|---|---|---|
| 0 Absent | Indicators copied from news; no owner | A named owner and a triage log | CTI0; HMM0 |
| 1 Consuming | Feeds and advisories triaged, alert-only; CTI as a secondary duty | Source register; every atomic indicator expires | FIRST Stage 1; CTI1 |
| 2 Requirements-driven | Reviewed PIR register; TIP; retro-hunts within days of credible advisories | PIR coverage ≥ 80% for two quarters; intelligence-to-action measured | FIRST Stage 2; CTI1–CTI2 |
| 3 Hunting programme | Written hunts on a cadence; detection requests and gap tickets tracked | Hunt conversion and gap closure reported monthly | HMM2, PEAK's minimum for most hunting organisations |
| 4 Intelligence-led | Internal intelligence shared; novel hunts; most hunts become detections; decisions cite products | Stakeholders can name decisions changed by intelligence | FIRST Stage 3; HMM3–HMM4; CTI2–CTI3 |

### Adoption roadmap: 30/60/90 days

| Window | Actions | Milestone and measure |
|---|---|---|
| Days 1–30 | Name the owner; draft five PIRs; source register; all feeds alert-only with expiry; join the sector ISAC | PIR register approved; all atomic indicators expiring |
| Days 31–60 | Agree templates with DetectionOps; Lab 1 for PIR-02; two recorded hunts; escalation and sharing rules with ResponseOps and Legal | First detection request accepted |
| Days 61–90 | Choose a TIP; first strategic brief; monthly outputs review; measure feed precision | First KPI report; one feed renewed or cancelled on evidence |

## Toolkit

### Checklists

**Quick start**
- [ ] One accountable owner and a backup
- [ ] Five to eight PIRs, each with a decision owner and review date
- [ ] Every feed rated and alert-only until its precision is measured
- [ ] Escalation path to the incident lead tested once

**Hunt readiness**
- [ ] Hypothesis written in ABLE form and linked to a PIR
- [ ] Data sources confirmed present for the time range
- [ ] Time box agreed; reviewer named
- [ ] Record template opened before the first query

**Sharing preflight**
- [ ] TLP label chosen and correct for every object
- [ ] Personal data removed unless the recipient needs it
- [ ] Approval recorded; legal basis known for this community
- [ ] Atomic indicators carry `valid_until`
- [ ] Decided whether `created_by_ref` or `where_sighted_refs` may reveal who was targeted; anonymise or omit if so

**Quarterly review**
- [ ] Every PIR confirmed, rewritten or retired with its owner
- [ ] Indicators past expiry removed from watchlists
- [ ] Feeds compared on precision and PIR answers
- [ ] One archived hunt rerun by someone else

### Templates

_Template status: plain-text forms; adapt the fields to your ticketing system._

```text
HUNT RECORD                                   ID: HUNT-2026-041   PIR: PIR-02
Hypothesis (ABLE)
  Actor:     identity-focused extortion crews
  Behavior:  MFA push flooding (T1621), then new MFA method (T1098.005)
  Location:  workforce IdP
  Evidence:  IdP sign-in and audit logs, 90 days
Scope and time box:  all workforce users; 3 working days
Data checked:        sources, fields, time range actually available
Queries:             link to repository commit
Verdict:             confirmed / refuted / inconclusive (why)
Would we have seen it?  yes / no (gap ticket ID)
Artefacts:           detection request, gap tickets, incident ID, brief
Reviewer and date:
```

```text
DETECTION REQUEST                              To: DetectionOps   From: ThreatOps
Behaviour and ATT&CK ID:   T1621, then T1098.005 (new MFA method) within 60 min
Why now:                   PIR-02; hunt HUNT-2026-041
Logic sketch:              >= 3 denials in 15 min, success from a new ASN (Lab 2 KQL)
Test data:                 synthetic file and one real true positive (if any)
Expected benign matches:   single denials; travel; new phones; users finishing MFA setup
Suggested response:        verify with user out of band; revoke sessions
Priority and due date:
```

```text
RFI LOG                                     ID: RFI-2026-017   Requester: Head of Payments
Question:         Is the phishing kit in ticket SEC-4412 linked to a known crew?
Due:              2026-10-20                   Related PIR: PIR-02 (none = PIR candidate?)
Answer and date:  probability word + confidence; sources rated A-F, 1-6
Recurring?        yes / no; if yes, propose a PIR at the quarterly review
```

```text
INTELLIGENCE BRIEF                             PIR: PIR-03     TLP:AMBER+STRICT
Bottom line:      one sentence with a probability word (e.g. "likely")
Confidence:       high / moderate / low, in a separate sentence, with reason
What we recommend: the decision you want and its owner
Key judgements:   2 to 4, each with its evidence and sources (rating A-F, 1-6)
What would change our view:
Gaps:
```

### Deep comparisons

| Option | Suits | Strength | Weakness |
|---|---|---|---|
| Consume only (ISAC, advisories, AIS) | Small teams, low targeting | Cheap, sector-relevant | No validation in your own data |
| Managed hunting or MDR (alone or with in-house PIRs and briefs) | Telemetry but no hunters | Expertise and coverage hours | Hunts may not follow your PIRs; without an internal owner and handoff contract, findings never become your detections |
| In-house ThreatOps | Targeted sectors, mature data | Context, PIR fit, detections you own | People, retention, legal and tooling cost |

### FAQ

**Is ThreatOps a job title or a team?** Some vendors name teams that way, such as Huntress's ThreatOps team, but there is no
common job family; the usual roles are CTI analyst and threat hunter.

**Do we need a threat intelligence platform?** Not on day one; see *Alternatives* under [Reference architecture](#reference-architecture).

**Should we auto-block indicators from feeds?** Only from feeds with high measured precision, with expiry, allowlists and a fast
manual override (see the [worked runbook](#worked-runbook-a-feed-indicator-blocks-a-shared-ip-illustrative)).

**How is hunting different from searching for IOCs?** A retro-hunt checks known indicators; a hunt tests a behaviour hypothesis that
may have no indicators at all, as in the Volt Typhoon case.[^volt]

**Can a two-person team do this?** Yes, at Levels 1–2 with occasional hunts, outsourcing the rest (see
[When to use](#when-to-use-and-when-not-to-use)).

## Going further

### Advanced topics and emerging direction

- **Adversaries using AI.** ATT&CK v20 adds "AI-focused and AI-enabled Techniques in Enterprise", so hunt backlogs will include
  them.[^attack-updates]
- **Autonomous hunting claims** are vendor marketing until evaluated as [AIOps for Security](../aiops-for-security/) describes;
  PEAK's model-assisted hunts (M-ATH) use machine learning but keep a hunter in charge.[^peak]
- **Standards gaps.** TAXII 2.1 reserves Channels (push sharing) but does not specify them,[^taxii21] and TLP 2.0 needs a STIX
  extension (Lab 3).
- **Maturity measurement.** CTI-CMM 1.3's roadmap planned version 2.0 for Q3 2026; on 2026-10-17 the site still offered 1.3.[^cticmm]

### Learning path

| Stage | Focus | Practice |
|---|---|---|
| Prerequisites | Log sources, SIEM queries, basic networking and identity | [SOC Ops](../soc-ops/), [SecDataOps](../secdataops/) |
| One day | Pyramid of Pain, ATT&CK structure, TLP | Lab 1 with your sector's groups |
| One week | PIRs, source ratings, WEP and confidence | Write three PIRs and one brief; Lab 2 |
| 30 days | PEAK hunt types; STIX and TAXII | Two recorded hunts; Lab 3; one detection request |
| Advanced | Diamond Model pivoting, baseline and model-assisted hunts, metrics | A quarterly PIR review and KPI report |

## Wrap-up

### Executive recap and cheat sheet

| Topic | Remember |
|---|---|
| Label | Ambiguous; the practices (CTI and hunting) are established |
| Start | Five to eight PIRs with decision owners |
| Indicators | Rate, label, alert-only, expire |
| Hunts | ABLE hypothesis, time box, record, artefact |
| Outputs | Detection requests, gap tickets, escalations, briefs |
| Standards | STIX 2.1, TAXII 2.1, TLP 2.0, ATT&CK v20 |
| Metrics | PIR coverage, intelligence-to-action, hunt conversion, gap closure, feed precision |
| Watch-outs | Feed hoarding, heat-map goals, unrecorded hunts, unexamined sharing law |

### A judgement call: a second feed or a hunter?

**Situation (illustrative).** A 2,000-person insurer has one CTI analyst, a SIEM with 30 days of retention, EDR on all endpoints
and budget for one option: a second commercial feed wired to auto-block, or a part-time hunter plus SIEM retention raised to
180 days for identity and EDR data.

**The case for the feed.** It is fast to deploy, produces visible numbers, and blocks known-bad infrastructure.

**The case for the hunter.** The insurer's PIRs centre on identity-led extortion (use case 2): valid accounts, few durable
indicators, so another feed adds little. But retention fills forward: raised today, it holds about 90 days of history after
three months and 180 after six, assuming nothing older survives elsewhere. Until then, "were we already hit?" reaches back only
30 days.

**Assumptions that decide it.** Detection engineering can absorb about two requests a month; the current feed's precision is
unknown; identity hypotheses such as Lab 2's need weeks of data, not months. Without detection capacity the hunter's findings
stall and the choice reverses, with managed hunting as a stopgap.

**Decision.** Raise retention now, the "fix data first" branch of the [decision framework](#decision-framework); meanwhile start
the hunter on hypothesis and baseline hunts over recent data, and measure the current feed's precision for 90 days. **Why the
attractive option can be wrong:** an auto-blocking feed raises activity metrics, adds outage risk (see the runbook) and does
nothing for the top PIR. **Uncertainty:** the first 90-day retro-hunt is possible around month 3, the first 180-day one at month 6; review then,
not at week 6.

### Learning objectives and mastery check

After this page you should be able to: explain why the label is ambiguous; write a PIR that meets FIRST's three criteria; place an
indicator on the Pyramid of Pain and choose its handling; write an ABLE hypothesis and test competing ones; package a finding
with TLP 2.0 in STIX 2.1; and choose between building, buying, going lean and fixing data first.

::: answer A stakeholder asks for "everything about ransomware". What do you do?
Turn it into PIRs that each ask one question for one decision, with an owner and a review date: for example "Which initial
access methods are ransomware affiliates using against our sector this quarter?"
:::

::: answer An ISAC shares 300 IP addresses at TLP:AMBER. How do you handle them?
Rate them, load them alert-only with a short `valid_until`, retro-hunt across retention, and share onward only within your
organisation and its clients, on a need-to-know basis.
:::

::: answer A three-day hunt for DNS tunnelling found nothing. Was it a failure?
Not if the record shows the DNS data covered the scope and the method would have revealed tunnelling: a confident negative,
ideally with a detection request. Incomplete data means a gap ticket.
:::

::: answer Two analysts disagree: is a login burst an intrusion or a broken script? How do you settle it?
List all hypotheses, check the assumptions behind each, then score every piece of evidence against all of them (ACH).
Evidence that fits both decides nothing; look for evidence only one explains, such as a new ASN or a new MFA method.
:::

::: answer Which KPI best shows that intelligence matters to the business, and why is it hard?
Intelligence-to-action rate: the share of products followed by a recorded decision or change. It is hard because consumers must
record what they did; agree that when the PIR is written.
:::

### Conclusion

"ThreatOps" is a weak label for strong practices: vendors stretch it at least three ways and standards bodies do not define it.
The work underneath is well documented: ask the right questions, judge sources, say how sure you are, test hypotheses
against your own data, and turn each answer into a defence that outlives the hunt. Value shows when PIR owners can name a decision that intelligence changed and the detection library holds rules that began
as hunts. If you cannot yet act on findings, consume, buy and fix your data first.

## Sources and further reading

Each line gives the date the source was last opened. The evidence ledger (`research/threatops-ledger.md`) maps claims to
sources and records what could not be fetched.

[^nist-ti]: [threat intelligence (glossary term)](https://csrc.nist.gov/glossary/term/threat_intelligence) — NIST CSRC Glossary, definition from SP 800-150. Checked 2026-10-16.
[^nist-gl]: [Glossary search for "threatops"](https://csrc.nist.gov/glossary?keywords-lg=threatops&sortBy-lg=relevance&ipp-lg=all) — NIST CSRC, no results. Checked 2026-10-16.
[^centripetal]: [How to Defeat Ransomware with ThreatOps](https://www.centripetal.ai/blog/how-to-defeat-ransomware-with-threatops-2) — Lauren Farrell, Centripetal, 2022-03-22. Checked 2026-10-16.
[^threatq]: [Company](https://threatq.com/company) — ThreatQuotient, undated. Checked 2026-10-17.
[^huntress]: [Huntress](https://catalog.appdirect.com/en-US/apps/333373/huntress) — AppDirect marketplace listing, vendor-supplied text, undated. Checked 2026-10-17.
[^s1]: [5 Years of SentinelOne ThreatOps](https://www.sentinelone.com/blog/5-years-of-sentinelone-threatops-defense-from-the-ground-up-to-global-threat-championships/) — Ryan O'Grady, SentinelOne, 2026-10-09. Checked 2026-10-17.
[^peak]: [Introducing the PEAK Threat Hunting Framework](https://www.splunk.com/en_us/blog/security/peak-threat-hunting-framework.html) — David Bianco, Splunk, 2023-04-18. Checked 2026-10-16.
[^peak-hypo]: [Hypothesis-Driven Hunting with the PEAK Framework](https://www.splunk.com/en_us/blog/security/peak-hypothesis-driven-threat-hunting.html) — David Bianco, Splunk, 2023-05-08. Checked 2026-10-17.
[^peak-baseline]: [Baseline Hunting with the PEAK Framework](https://www.splunk.com/en_us/blog/security/peak-baseline-hunting.html) — David Bianco, Splunk, 2023-07-11. Checked 2026-10-17.
[^peak-detect]: [Turning Hunts Into Detections with PEAK](https://www.splunk.com/en_us/blog/security/peak-turning-hunts-into-detections.html) — David Bianco, Splunk, 2023-07-26. Checked 2026-10-16.
[^peak-metrics]: [Measuring Hunting Success with PEAK](https://www.splunk.com/en_us/blog/security/peak-threat-hunting-metrics.html) — David Bianco, Splunk, 2023-08-02. Checked 2026-10-16.
[^first-pir]: [Priority Intelligence Requirement (PIR)](https://www.first.org/global/sigs/cti/curriculum/pir) — FIRST CTI SIG curriculum. Checked 2026-10-17.
[^first-mh]: [Machine and Human Analysis Techniques (and Intelligence Cycle)](https://www.first.org/global/sigs/cti/curriculum/machine-human) — FIRST CTI SIG curriculum. Checked 2026-10-17.
[^first-methods]: [Methods and Methodology](https://www.first.org/global/sigs/cti/curriculum/methods-methodology) — FIRST CTI SIG curriculum. Checked 2026-10-17.
[^first-source]: [Source Evaluation and Information Reliability](https://www.first.org/global/sigs/cti/curriculum/source-evaluation) — FIRST CTI SIG curriculum. Checked 2026-10-17.
[^first-wep]: [Communicating Uncertainties in CTI Reporting](https://www.first.org/global/sigs/cti/curriculum/cti-reporting/) — FIRST CTI SIG curriculum. Checked 2026-10-17.
[^first-stages]: [Program maturity stages](https://www.first.org/global/sigs/cti/cti-program/program-stages) — FIRST CTI SIG. Checked 2026-10-16.
[^first-stage1]: [CTI Maturity model – Stage 1](https://www.first.org/global/sigs/cti/cti-program/stage1) — FIRST CTI SIG. Checked 2026-10-16.
[^first-stage2]: [CTI Maturity model – Stage 2](https://www.first.org/global/sigs/cti/cti-program/stage2) — FIRST CTI SIG. Checked 2026-10-16.
[^first-stage3]: [CTI Maturity model – Stage 3](https://www.first.org/global/sigs/cti/cti-program/stage3) — FIRST CTI SIG. Checked 2026-10-16.
[^cia-sat]: [A Tradecraft Primer: Structured Analytic Techniques for Improving Intelligence Analysis](https://www.cia.gov/resources/csi/static/Tradecraft-Primer-apr09.pdf) — US Government (CIA), March 2009. Checked 2026-10-17.
[^cticmm]: [CTI-CMM Version 1.3](https://cti-cmm.org/) — DeBolt, Connor, Beckwith et al., January 2026 (PDF linked from the site). Checked 2026-10-17.
[^killchain]: [Intelligence-Driven Computer Network Defense Informed by Analysis of Adversary Campaigns and Intrusion Kill Chains](https://www.lockheedmartin.com/content/dam/lockheed-martin/rms/documents/cyber/LM-White-Paper-Intel-Driven-Defense.pdf) — Hutchins, Cloppert and Amin, Lockheed Martin, 2011. Checked 2026-10-16.
[^diamond]: [The Diamond Model of Intrusion Analysis](https://www.activeresponse.org/wp-content/uploads/2013/07/diamond.pdf) — Caltagirone, Pendergast and Betz, 2013. Checked 2026-10-17.
[^pyramid]: [The Pyramid of Pain](https://detect-respond.blogspot.com/2013/03/the-pyramid-of-pain.html) — David J. Bianco, 2013-03-01, updated 2014-01-17. Checked 2026-10-16.
[^attack-updates]: [Updates – October 2026 (ATT&CK v20)](https://attack.mitre.org/resources/updates/) — MITRE ATT&CK, 2026-10-13. Checked 2026-10-16.
[^attack-tactics]: [Enterprise tactics](https://attack.mitre.org/tactics/enterprise/) — MITRE ATT&CK, v20. Checked 2026-10-16.
[^attack-t1098]: [Account Manipulation: Device Registration (T1098.005)](https://attack.mitre.org/techniques/T1098/005/) — MITRE ATT&CK v20. Checked 2026-10-17.
[^attack-faq]: [ATT&CK FAQ](https://attack.mitre.org/resources/faq/) — MITRE ATT&CK. Checked 2026-10-16.
[^attack-stix]: [attack-stix-data](https://github.com/mitre-attack/attack-stix-data) — MITRE, ATT&CK in STIX 2.1. Checked 2026-10-17.
[^attack-taxii]: [TAXII 2.1 API User Guide](https://github.com/mitre-attack/attack-workbench-taxii-server/blob/main/docs/USAGE.md) — MITRE ATT&CK Workbench TAXII server. Checked 2026-10-17.
[^stix21]: [STIX Version 2.1](https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html) — OASIS Standard, 2021-06-10. Checked 2026-10-17.
[^taxii21]: [TAXII Version 2.1](https://docs.oasis-open.org/cti/taxii/v2.1/os/taxii-v2.1-os.html) — OASIS Standard, 2021-06-10. Checked 2026-10-16.
[^tlp2-stix]: [TLP 2.0 extension definition](https://github.com/oasis-open/cti-stix-common-objects/tree/main/extension-definition-specifications/tlp-2.0) — OASIS CTI TC, cti-stix-common-objects repository. Checked 2026-10-16.
[^tlp]: [Traffic Light Protocol (TLP) — Version 2.0](https://www.first.org/tlp/) — FIRST, authoritative from August 2022. Checked 2026-10-17.
[^sp800150]: [SP 800-150, Guide to Cyber Threat Information Sharing](https://csrc.nist.gov/pubs/sp/800/150/final) — Johnson et al., NIST, October 2016. Checked 2026-10-16.
[^sp80053]: [SP 800-53 Rev. 5 catalog (OSCAL JSON, release 5.2.0): RA-10, PM-16, RA-3(3)](https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_catalog.json) — NIST, updated 2026-05-11. Checked 2026-10-16.
[^csf11]: [Framework for Improving Critical Infrastructure Cybersecurity, Version 1.1](https://nvlpubs.nist.gov/nistpubs/CSWP/NIST.CSWP.04162018.pdf) — NIST, 2018-04-16 (ID.RA-2, p. 26). Checked 2026-10-17.
[^csf2]: [The NIST Cybersecurity Framework (CSF) 2.0](https://nvlpubs.nist.gov/nistpubs/CSWP/NIST.CSWP.29.pdf) — NIST CSWP 29, 2024-02-26. Checked 2026-10-16.
[^sp80053b]: [SP 800-53B, Control Baselines for Information Systems and Organizations](https://csrc.nist.gov/pubs/sp/800/53/b/upd1/final) — NIST, 2020 (release 5.2.0, August 2025, baselines unchanged). Checked 2026-10-17.
[^nis2]: [Directive (EU) 2022/2555 (NIS2), Article 29](https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32022L2555) — EUR-Lex, 2022. Checked 2026-10-16.
[^crs]: [The Cybersecurity Information Sharing Act of 2015: Expiring Provisions (IF12959)](https://www.everycrsreport.com/files/2026-09-03_IF12959_e88b818ccb3aca205dcf1ba233b57cd55207205b.html) — Congressional Research Service, updated 2026-09-03 (EveryCRSReport copy). Checked 2026-10-16.
[^ais]: [Automated Indicator Sharing (AIS)](https://www.cisa.gov/topics/cyber-threats-and-advisories/information-sharing/automated-indicator-sharing-ais) — CISA. Checked 2026-10-16.
[^isacs]: [About ISACs](https://www.nationalisacs.org/about-isacs) — National Council of ISACs. Checked 2026-10-16.
[^misp]: [MISP features and functionalities](https://www.misp-project.org/features/) — MISP project. Checked 2026-10-16.
[^misp-home]: [MISP Open Source Threat Intelligence Platform](https://www.misp-project.org/) — MISP project; news lists 2.5.x security releases (October 2026). Checked 2026-10-17.
[^opencti]: [OpenCTI](https://github.com/OpenCTI-Platform/opencti) — Filigran, GitHub README. Checked 2026-10-16.
[^volt]: [AA24-038A: PRC State-Sponsored Actors Compromise and Maintain Persistent Access to U.S. Critical Infrastructure](https://www.cisa.gov/news-events/cybersecurity-advisories/aa24-038a) — CISA, NSA, FBI and partners, 2024-02-07. Checked 2026-10-17.
[^mtrends]: [M-Trends 2026: Data, Insights, and Strategies From the Frontlines](https://cloud.google.com/blog/topics/threat-intelligence/m-trends-2026) — Jurgen Kutscher, Google Cloud (Mandiant), 2026-03-23. Checked 2026-10-16.
[^entra-signin]: [Azure Monitor Logs reference: SigninLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs) — Microsoft Learn, 2026-08-27. Checked 2026-10-17.
[^entra-500121]: [How to troubleshoot sign-in errors](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-troubleshoot-sign-in-errors) — Microsoft Learn, 2024-11-11. Checked 2026-10-17.
[^entra-mfa]: [Sign-in event details for Microsoft Entra multifactor authentication](https://learn.microsoft.com/en-us/entra/identity/authentication/howto-mfa-reporting) — Microsoft Learn, 2025-06-24. Checked 2026-10-17.
[^entra-audit]: [Azure Monitor Logs reference: AuditLogs](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/auditlogs) — Microsoft Learn, 2026-08-27. Checked 2026-10-17.
[^entra-audit-ref]: [Microsoft Entra audit log activity reference](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/reference-audit-activities) — Microsoft Learn, 2025-03-25. Checked 2026-10-17.
[^mandia]: [Prepared Statement of Kevin Mandia, CEO of FireEye](https://oversightdemocrats.house.gov/sites/evo-subsites/democrats-oversight.house.gov/files/Mandia%20Testimony.pdf) — US House Committees on Oversight and Reform and on Homeland Security, 2021-02-26. Checked 2026-10-16.

**Further reading:** the full [FIRST CTI SIG curriculum](https://www.first.org/global/sigs/cti/curriculum/).

**Changelog**

- 2026-10-16 — First version: term status set to ambiguous (matrix proposed niche; see ledger section A); research, labs executed
  and diagrams by the managing author. Independent review pending.
- 2026-10-17 — Review r1 revision: vendor senses, SP 800-53 baselines and retention lead time corrected; ACH, RFIs, incident
  scoping and T1098.005 added; labs re-run; repetition cut.
- 2026-10-17 — Review r1, second pass: Figures 1, 2 and 6 redrawn for phones; decision tree reconciled with *When to use*;
  revert authority for blocks; Entra KQL sketch; TLP labels, acronyms, RFI log; widest tables narrowed; dated facts out of the
  takeaways.
- 2026-10-17, post-score polish: 500121 MFA-setup caveat (KQL sketch, detection request); baseline-hunt entry in Figure 4;
  NIS2 text re-checked; restatements cut.
