Incident Response & DFIR

During an incident the question is never interesting. It is just urgent.

Is this hostname a live credential-harvesting site, yes or no, and how long has it been one? A DNS-verified list of currently-resolving phishing domains answers that in a single call, answers it for a hundred hosts at a time when you are scoping a log extract, and puts a date on it when you need to know how far back to hunt.

390,000+DNS-verified phishing domains, all currently resolving
100 per callBatch endpoint ceiling, one credit per domain checked
Under 50 msTypical lookup latency, so triage never waits on it
Daily changelogAdded and removed records you can date a compromise against
User-reported phishing queues
Proxy and DNS log scoping
Alert enrichment before escalation
Retro-hunting historical logs
Handover to threat intel
Home / Use Cases / Incident Response
The shape of the problem

Triage is a queue, and the queue is mostly one repeated question

Nothing about validating a domain is intellectually hard. It is just that you have to do it forty times before lunch, under pressure, while somebody senior asks whether it is contained yet.

Anyone who has run a phishing queue knows the rhythm. A report lands from a user who forwarded something odd. A detection fires on a URL in a message body. An endpoint alert mentions an outbound connection to a hostname nobody recognises. In every case the analyst has the same first task, and it is not a task that rewards creativity: establish, quickly and with something defensible in a write-up, whether this host is hostile. Only after that answer exists does the rest of the response — scope, contain, notify, remediate — have anything to hang on. Until it exists, every downstream decision is a guess with a ticket number attached.

The tools you would otherwise reach for

The reason this consumes so much of a shift is that the natural tools for it are slow and each answers a slightly different question. Laid side by side, the trade-off is easier to see than to argue about.

What you reach forWhat it actually tells youWhat it costs mid-triage
Registration age That the domain is new, which is suggestive and not conclusive. Seconds, but plenty of legitimate hosts are new and plenty of hostile ones are aged deliberately, so somebody still has to decide.
Passive DNS Where a name has pointed over time, which is genuinely useful for infrastructure pivoting. Largely irrelevant to the yes-or-no you actually need right now, and it invites a tangent the queue cannot afford.
Sandbox detonation A real answer about what the page does when a browser reaches it. Minutes per sample, a judgement call about what you are looking at, and occasionally a signal to the operator that somebody is looking.
DNS-verified known-bad lookup Whether this exact hostname is a confirmed phishing host that is still resolving. One credit and typically under 50 ms, with a category, a DNS status and a last-checked date attached to the answer.

Stacked together, the first three produce a good analysis and a bad queue — and the analysis was never the bottleneck.

Definition

What a hit actually asserts

A hit means the verdict came from infrastructure that observed the domain, confirmed it was serving phishing content, and confirmed by DNS resolution that it is still up — which means you are not looking at a stale indicator from a feed that has been accumulating dead entries for years. You get a category, a DNS status, a last-checked date and a confidence value in the same response, and you get them in the time it takes the request to travel.

Why it has to be wired in rather than bookmarked

What makes this worth automating is that it survives contact with volume. One analyst checking one domain by hand is fine. The same analyst facing a campaign that hit four hundred mailboxes with three rotating link domains, plus a proxy extract of every host those mailboxes touched afterwards, is not fine — and that is the normal shape of a phishing incident rather than an unusual one. The mail-side controls that caught the first wave will not have caught the second, and the difference between a two-hour scoping exercise and a two-minute one is entirely a question of whether the lookup is scripted.

Deliberation ends at the hit

A known-bad lookup against a list of verified live phishing domains solves a narrow slice of triage and solves it completely. If the host is in the list you are done deliberating: the analyst stops investigating and starts responding, and that transition is what actually shortens an incident.

The clock nobody in your room controls

Speed here is not a vanity metric. The clock on a phishing incident is the attacker's session with a harvested credential, and every minute between the first click and the account lock is a minute in which mailbox rules get created and MFA methods get registered. Cutting ten minutes off identification moves containment closer to the click, which is the only variable that reliably changes the outcome.

The verdict is a DNS fact, not a score. Every domain in the list has been confirmed to resolve. Hosts that go dark are dropped from the database rather than retained, so a hit means "this is live right now" — precisely the property you want when deciding whether to sinkhole something.
Never call this from the browser. The key is passed as a query parameter or in the POST body and belongs on a server. If your enrichment sits in a web console, put a small internal endpoint of your own in front of it rather than shipping the key to an analyst's browser tab.
Scoping

Who else clicked: the batch endpoint against a log extract

The highest-value use of this data during an incident is not checking the reported domain. It is checking every domain your estate touched around the same time.

Scoping is where phishing incidents are won or lost, and it is the part that most often gets short-changed because it is tedious. You know one user clicked. You need to know how many others did, whether any of them reached a different host in the same campaign, and whether anything else in the estate has been talking to that infrastructure for longer than you assumed. The evidence for all three questions is already sitting in your proxy logs, your resolver logs and your mail gateway's URL-rewrite records. It just arrives as tens of thousands of rows and no verdicts.

The mechanical answer, which is boring and effective

Pull the distinct hostnames from the relevant window — usually the twelve hours either side of first delivery, sometimes wider — normalise them to bare hostnames, strip the ones you already know are yours or are obviously ordinary infrastructure, and push what remains through POST /api/v1/batch in slices of a hundred. The body is a JSON object holding your key and a domains array; the ceiling is a hundred domains per request and the cost is one credit for each domain checked. A distinct-host extract from a mid-sized estate over a day is frequently in the low thousands, which is a handful of requests against a package that holds a hundred thousand credits.

The hits give you names and timestamps

Every hostname that matches is a confirmed live phishing host that something on your network resolved or fetched, which converts a vague "we think about six people were affected" into a list of source addresses and times you can act on.

The misses are the real product

Hosts that do not match drop out of consideration for this pass, so the senior analyst's remaining manual work is bounded and prioritised rather than open-ended. The win is not the hits — it is that the pile of things still needing a human shrank by two orders of magnitude in a single job.

The same extract over a longer window is a retro-hunt

Because the list is rebuilt every 24 hours and only carries hosts that currently resolve, today's copy describes today's live infrastructure — but the campaign you are investigating may have started weeks ago, and the domains that carried it may still be up. Feeding a ninety-day distinct-host extract through the batch endpoint routinely surfaces connections that nobody alerted on at the time, because the domain was not yet known-bad when the connection happened. That is not a failure of your detection stack; it is the ordinary consequence of blocklists being a lagging record of what has been observed, and it is exactly why the retro pass belongs in the runbook rather than in somebody's good intentions.

When the scoping query stops being an API call

Teams that do this often stop pulling extracts by hand and put the whole database next to their log platform instead. The daily feed delivers the complete list as CSV on its own subscription, along with the added and removed changelog, and once it is loaded into a lookup table the scoping question becomes a join rather than a request. That is the pattern described on the SIEM integration page, and it is the right answer for anyone running the query repeatedly rather than during one bad afternoon.

Batch, do not loop. A hundred hostnames in one request costs the same hundred credits as a hundred single calls, but it is one round trip instead of a hundred, and it gives your job a single response to attach to the ticket rather than a hundred lines of noise.
Normalise before you send. Strip schemes, ports, paths and trailing dots, lowercase everything, and de-duplicate. A raw proxy extract will otherwise burn credits checking the same host in eleven spellings, and it will make your hit count wrong in the write-up.
Reading the answer

What "not in the list" means, and what it does not

The most dangerous moment in any enrichment pipeline is when a clean result gets treated as an exoneration and an alert auto-closes.

A hit is unambiguous. The domain was observed, verified as serving phishing, and confirmed as resolving in DNS at the last check. You can escalate on it, block on it, and cite it in the incident record without qualification. That clarity is the whole value proposition, and it is worth stating plainly precisely so that the opposite case gets stated just as plainly.

A miss means one thing only

It means this hostname is not in this database. It does not mean the host is benign, it does not mean nobody has reported it, and it certainly does not mean your user is fine. The honest failure modes are easy to enumerate:

  • Infrastructure younger than observation. A domain registered ninety minutes ago and used for the first time this afternoon will not be there, because nothing has observed it yet.
  • A compromised legitimate site. A trusted host serving a phishing kit on one path is not a hostile domain and will not appear as one.
  • Delivery that never uses a hostile hostname. A payload on a file-sharing service, a link buried in a document, or a landing page reached through an open redirect on a platform you trust will all pass a hostname check cleanly — in each case the hostname is not the thing that is wrong.

Escalate on a hit, never close on a miss

This is the single thing on the page most worth getting right when you automate triage. A miss should return the alert to the queue in its original state, with the enrichment recorded as "not present in the known-bad list at 14:22" rather than as a verdict.

What auto-closing actually builds

If your playbook closes tickets on a clean lookup, you have built a system that reliably discards exactly the alerts that most needed a human — the ones involving infrastructure too new or too unusual to be in anybody's list yet. That is worse than not enriching at all, because it launders an absence of evidence into a decision.

A floor rather than a ceiling

Framed correctly, a floor is genuinely useful. It removes the volume of known infrastructure from your analysts' attention so their judgement is spent on the residue, and it gives you a fast, defensible, timestamped statement of fact for the incident record. It does not replace sandboxing, it does not replace the mail gateway, it does not replace the judgement of the person reading the message, and it is not a detection engine. Any vendor claim to the contrary should make you suspicious, and this one is not making it. Pair it with the layers described on the DNS filtering and threat intelligence pages and it does the job it is good at while something else covers the rest.

Write the miss into the ticket, not into the outcome. "Domain absent from the DNS-verified known-bad list at 14:22" is a useful line in a timeline. "Auto-closed: domain clean" is a line you will read again during a post-incident review, in a much less comfortable meeting.
Where it sits

One link in the enrichment chain, placed early and cheaply

The check belongs before the expensive steps, not after them, because its whole job is to stop the expensive steps from running unnecessarily.

Report or alert arrives
URLs extracted, hosts normalised
Known-bad lookup
Hit escalates, miss stays queued
Containment and scoping

Ordering matters more than it looks. Detonation, manual analyst review and infrastructure pivoting are all expensive in wall-clock time or in attention, and a meaningful share of what arrives in a phishing queue is already-known infrastructure that needs none of them. Putting the cheap lookup first means the expensive capacity is spent on the residue rather than on re-deriving a conclusion that was already available for a fraction of a cent.

The four numbers that decide whether it fits your pipeline

They are deliberately mechanical: how big the list is, how often the picture is refreshed, what a lookup costs at the volumes a response team actually runs, and how long unused capacity survives.

390,000+Active phishing domains, each verified as currently resolving in DNS
24 hFull rebuild cycle, with an added and removed changelog for every build
$0.0025Per lookup on the $249 Professional package of 100,000 credits
12 monthsCredit validity, so a reserve bought before a bad week does not expire
The first hour

Where the lookup lands in a real response sequence

Six steps in the order they actually happen, with the domain check doing exactly one job in each of them.

1
Minute 0

The report lands and the host gets validated

A user forwards a message, or a detection fires. The playbook extracts every URL from body, headers and any rewritten gateway links, reduces them to distinct hostnames, and runs a single check. If a hostname matches, the ticket is reclassified as a confirmed phishing incident before anybody has read the email carefully. That reclassification is what lets the rest of the sequence proceed without a debate.

2
Minute 5

Search the mail platform for the same hosts

The confirmed hostname becomes the search term. Every mailbox holding a message that contains it is now a known recipient, which gives you the delivery population without waiting for more users to report. Purge or quarantine at this point rather than later, because messages sitting unread are still capable of producing a click twenty minutes from now.

3
Minute 10

Scope the clicks from proxy and resolver logs

Delivery is not interaction. Query proxy and DNS logs for the confirmed hostnames across the delivery window to separate the people who received it from the far smaller group who resolved or fetched it. This is the list that drives credential resets, and getting it right is the difference between resetting six accounts and resetting six hundred.

4
Minute 20

Widen to the rest of the campaign

Take the distinct-host extract from the same window and batch it. Campaigns rotate hosts, and the domain in the reported message is frequently not the only one your users reached — a redirect chain, a second wave on different infrastructure, or a follow-up message nobody bothered to report. This pass finds the ones you were not told about.

5
Minute 30

Contain the infrastructure, then the identities

Sinkhole or block the confirmed hostnames at the resolver and the proxy so a late click produces a block page rather than a login form. Then work the identity side: reset credentials, revoke sessions and refresh tokens, and audit the affected mailboxes for rules created since the first delivery. The rule is the part people forget, and it is the part that survives the reset.

6
Minute 60

Look backwards before you close

Before the incident is written up, run the confirmed hostnames against a longer log window — thirty, sixty, ninety days — to establish whether this infrastructure has been reached before. A hit outside the incident window changes the scope, the notification obligations and the conclusion, and finding it after the ticket closes is materially worse than finding it now.

Containment

The checklist once a phishing host is confirmed

Tick these off as you work. Nothing is stored or transmitted — the state resets on reload — and it exists so that nothing gets skipped at two in the morning.

Containment progress 0 of 8 steps marked

1. Record the verdict with its timestamp

Capture the full response — domain, category, DNS status, last-checked date, confidence — into the case record before you do anything else. The database is rebuilt daily, so the answer you got at 14:22 is the evidence for the write-up, and re-running the query next week will not reproduce it if the host has since gone dark.

Evidence: the raw response body

2. Block the hostname at the resolver and the proxy

Resolver-level blocking covers every device and every protocol rather than only browsers, and it stops late clicks from users who have not read the warning email yet. Add the proxy rule as well, so hard-coded addresses and cached resolutions do not slip past while the DNS change propagates through the estate.

Covers late clicks and non-browser traffic

3. Purge the message from every mailbox that holds it

Search on the confirmed hostname rather than the subject line or the sender address, both of which vary across a campaign while the link destination frequently does not. Purge rather than quarantine where your platform allows it, and record the count of messages removed as part of the incident scope.

Search by host, not by subject

4. Separate recipients from people who actually clicked

Resolver and proxy logs give you the interaction set. Treat that as the reset population and the wider delivery list as the notification population — conflating the two produces either an under-response or an estate-wide password reset that nobody will thank you for and that buries the real signal.

Two populations, two actions

5. Reset credentials and revoke every live session

A password change alone leaves existing session tokens and refresh tokens valid, which is how an attacker keeps a foothold through what looks like clean remediation. Revoke sessions, invalidate tokens, and review registered MFA methods for anything enrolled after the first delivery timestamp.

Sessions and MFA methods, not just passwords

6. Audit affected mailboxes for rules and delegations

Forwarding rules, inbox rules that file replies into an obscure folder, and newly granted delegate access are the standard persistence mechanisms after a mailbox compromise, and every one of them survives a password reset. Check them explicitly for each account in the interaction set rather than assuming.

Persistence survives the reset

7. Batch the campaign's wider host list

Take every distinct hostname from the delivery window, slice it into hundreds, and run it through the batch endpoint. This is where second-wave infrastructure and unreported follow-up messages surface, and it is the step most likely to change the scope of an incident you had already decided was bounded.

100 domains per request, 1 credit each

8. Hand the confirmed indicators to threat intel

Confirmed hostnames, first-seen dates from the changelog, delivery timestamps and the observed lure all belong with whoever runs detection engineering, so the campaign shape informs future rules rather than dying with the ticket. The handover pattern is set out on the threat intelligence page.

Close the loop with detection engineering
Dating the compromise

Using the daily changelog to say when a host became known-bad

Knowing a domain is hostile is triage. Knowing roughly when it became known is what tells you how far back to hunt and what your stack could reasonably have caught.

Every rebuild of the database produces a changelog of domains added and removed on that day, and that record is more useful during an investigation than it first appears. When a host first appears in an added list, you have an outer bound on when it became known infrastructure. Compare that date against the timestamp of the connection you found in your logs and exactly one of two readings is true — and because the two findings lead to completely different actions, turning up to a post-incident review with dates rather than impressions is the difference between a defensible conclusion and an argument.

The connection came after the add date

The host was already known when your estate reached it, so the interesting question is why nothing blocked it. That points at a gap in enforcement — a resolver that was not consuming the list, a proxy category not applied to a segment, a device sitting on a bypass path.

The connection came before the add date

Nothing in your stack could have known, so the appropriate response is a wider retro-hunt rather than a root-cause conversation about controls. That points at detection coverage and dwell time, and the correct remediation is to widen the hunting window rather than tighten a control that was working as designed.

What a removal tells you

The removal side of the changelog carries information too. A domain leaving the list means it stopped resolving, which for phishing infrastructure usually means the operation moved on or the host was taken down. If a domain in your incident disappears from the list two days after your first observed connection, that was a short-lived campaign and the window you are hunting in is correspondingly narrow. If it persists across weeks of builds, the infrastructure is durable, the campaign was probably not aimed only at you, and the retro-hunt should be wider and the intel handover more detailed.

Two ways to get at the dates

Teams doing occasional investigative work call GET /api/v1/check and read last_checked from the response. Teams that want the historical picture take the daily feed — the full database as CSV plus the added and removed changelog, on its own subscription — and keep the daily diffs as a local first-seen table, which turns the whole question into a local join with no per-query cost. There is also a database-stats endpoint reporting current size and last-update time, which is worth calling from your pipeline's health check so that a silently stale local copy is noticed by a monitor rather than by an analyst mid-incident.

Single check during triage, then a batch pass over a log extract
# One host, straight from the ticket
curl -s "https://phishingdetectionapi.com/api/v1/check?domain=login-verify-portal.example&apikey=YOUR_KEY"

# Response
# {"domain":"login-verify-portal.example","is_phishing":true,"category":"phishing",
# "dns_status":"resolves","last_checked":"2026-07-27","confidence":0.98,
# "database_size":390000}

# Distinct hosts from a proxy extract, 100 at a time, 1 credit per domain
cut -d, -f3 proxy_window.csv | tr 'A-Z' 'a-z' | sort -u | split -l 100 - hosts_
for f in hosts_*; do
 jq -Rn --arg k "$API_KEY" '{apikey:$k, domains:[inputs]}' < "$f" \
 | curl -s -X POST https://phishingdetectionapi.com/api/v1/batch \
 -H "Content-Type: application/json" -d @- \
 | jq -r '.results[] | select(.is_phishing) | [.domain.category.last_checked] | @tsv'
done
Keep the raw response, not a summary. A one-line "confirmed phishing" note in a ticket is worth very little six months later. The full response, with its last_checked date and the database_size at the time of the query, is a dated artefact you can put in front of an auditor, a regulator or a cyber insurer.
lookups reset each month. That suits incident work, which is bursty rather than steady. A package bought in January is still there for the campaign that arrives in September, and a quiet quarter does not cost you the balance.
Questions from the console

What responders ask before they wire this in

Mostly reasonable objections about coverage, cost, and where a lookup belongs in an automated pipeline.

Does this replace our sandbox or our mail gateway?

No, and building the pipeline as though it does would be a mistake. It answers one question — is this hostname a currently-live, verified phishing host — and answers it faster and more cheaply than any detonation. It does not analyse content, evaluate a page it has never seen, or catch a hostile path on an otherwise legitimate domain.

  • The right mental model is a cheap first filter. It removes known infrastructure from the queue so the expensive tools are spent on what remains.
  • Your gateway is untouched. It still catches what it catches; the lookup runs on whatever got through and was reported.
  • Your sandbox still runs, on the unknowns. What stops is both tools repeatedly re-deriving conclusions that were already available.
What do we do about domains registered in the last few hours?

They will not be in the list, and no known-bad list will have them, because nothing has observed them yet. This is the structural limit of the approach and it is better acknowledged than papered over. If a domain is hours old and being used against you right now, your defence is registration-age heuristics, content analysis, user reporting and the speed of your containment — not a blocklist.

  • What the list contributes instead is the retro-hunt. When the host is eventually observed and added, a scheduled re-check of your recent log extract surfaces every connection your estate already made to it.
  • That is why the retro pass belongs in the runbook. It converts a gap you cannot close in real time into a detection you get slightly late rather than never.
How many credits does a realistic incident actually consume?

Fewer than teams expect, because incident work is bursty and bounded. A single triage lookup is one credit. Scoping a day's distinct-host extract from a mid-sized estate is typically a few thousand. A ninety-day retro-hunt over distinct hosts might be tens of thousands in one pass, and you run it once rather than continuously.

  • $249 Professional. 100,000 credits at $0.0025 per lookup, which covers most response teams comfortably.
  • $499 Business. 250,000 credits at $0.0020 per lookup, which suits teams that also run scheduled retro passes.
  • Twelve-month validity. Buying capacity ahead of a bad week does not waste it if the week never comes.
Can we run this from a playbook without exposing the key?

Yes, and you should. The key is passed as a query parameter on the check endpoint or in the JSON body on the batch endpoint, which means it belongs in server-side automation — your orchestration platform, a scheduled job, a small internal service — and never in anything that reaches an analyst's browser.

  • Put a thin internal endpoint in front of it. It holds the key, applies your own normalisation and de-duplication rules, and returns the verdict to whatever asked.
  • You get one place to log every lookup. Useful for the ticket record, and for spotting a runaway job before it eats a package.
Should we use the API or take the daily feed?

Use the API when the volume is unpredictable and the lookups are conversational: an analyst validating a host, a playbook enriching an alert, a one-off batch pass over an extract during an incident. That is the natural shape of response work and it maps cleanly onto credits.

  • Take the daily feed when you want the whole database locally. As a lookup table beside your log platform, as a blocklist on your resolvers, or as the basis of a first-seen history built from the daily added and removed changelog.
  • It is a separate subscription. It makes scoping queries free at the point of use, which matters once retro-hunting is a scheduled job rather than an occasional favour — delivery options are on the daily feed page.
How do we cite this in an incident report or a regulatory notification?

Cite the response, not the conclusion. Record the domain queried, the timestamp of the query, and the returned fields — is_phishing, category, dns_status, last_checked and confidence. That is a dated, reproducible artefact describing what was known at the moment you acted, which is the standard a report needs to meet.

Do not over-claim in the narrative. The defensible statement is that the domain was present in a database of DNS-verified active phishing hosts at the time of the check. The statement to avoid is any implication that the absence of a second domain from that list established the second domain as safe.
Does the list carry dead domains that will pollute our indicators?

No. Inclusion requires the domain to be confirmed as currently resolving in DNS, and hosts that stop resolving are dropped from the database rather than retained. That is why the active count sits around 390,000 rather than growing without limit, and it is the property that makes the list usable as a blocklist instead of merely as a historical archive.

  • A resolver blocklist stays loadable. The list stays small enough to load and match quickly rather than growing into an archive.
  • A hit means live right now. Exactly the input a containment decision needs, rather than a report that something was hostile at some point in the past.

Put a one-credit answer in front of every escalation decision

Wire the check into the front of your phishing queue, batch your log extracts a hundred hosts at a time, and keep the daily changelog so you can date what you find. The endpoints and response shapes are documented, and monthly plans are priced per lookup with a twelve-month life.