Our domain showed up in a breach: what does a credential-exposure alert actually tell us, and what should we do?

DedSec Security Research ·

Suppose an alert arrives: forty-one addresses at your domain have appeared in "a new breach". Some rows show a password, some a string of hex, some a URL. Someone asks whether those people need to reset their passwords. The honest answer is that it depends on what kind of record each row is, when it was really taken, which account the address maps to, and what was on the device it came from. The alert usually tells you none of that directly.

The breach and brand monitoring post made the case for watching credential exposure, and named three things that decide whether it works: freshness, identity resolution and the reset loop. This post goes underneath them: where exposed credentials come from and why the source changes the response, why one record carries three dates, how an address does or does not map to a working credential, what to do for each class, how to stop breached passwords being set again, and what to ask of any alert.

The worked example uses the reserved domain example.com and is invented. NIST statements are quoted from SP 800-63B-4, retrieved from pages.nist.gov on 24 October 2026. Statements about the Have I Been Pwned (HIBP) APIs come from its v3 API documentation, retrieved the same day, plus one live request to the Pwned Passwords range endpoint. Publication dates are from the CSRC publication page. Everything else is general practice, not a description of how any product, ours included, processes these records.

Three kinds of record that all look like "a leak"

Exposed credentials reach monitoring by three routes. They often arrive in the same feed and the same table, and they mean different things.

A dump from one breached service

Someone compromises a single service and takes its user table: an email address, perhaps a username, and whatever the service stored in place of the password. That last column decides almost everything.

Two inferences follow. A slow-hashed dump is a weaker signal about any individual credential, but not a reason to do nothing, because the people with weak passwords are the ones most likely to reuse them. And a plaintext password attributed to a service known to store slow hashes was either cracked from that database's hashes, captured somewhere else (phishing, malware, a server logging passwords at login), or wrongly attributed. Only the first belongs in this class. Often you will not know the storage scheme at all. Treat unknown as recoverable.

Combolists

A combolist is an aggregate: email-and-password pairs merged from earlier dumps, cracked hashes and other combolists, and redistributed as input for credential-stuffing tools. They are commonly reposted, often under a new name and billed as fresh. Three consequences for triage:

Some corpora keep provenance. HIBP's breach model carries flags including IsVerified, IsFabricated (data "unlikely to have been hacked from the indicated website"), IsSpamList ("the data has not come as a result of a security compromise") and IsMalware. Whatever feed you use, ask whether it tells you which class a record is, or flattens them into one list.

Infostealer logs

An infostealer is malware on an endpoint. It collects what the browser stores, typically saved passwords with the URL each was used on, cookies and autofill data, and sends it to an operator; the logs are sold or shared in bulk. This class is different and more urgent, for four reasons.

  1. The URL names the service. A dump says an address was registered on someone else's site. A stealer log row says the credential was typed into a specific URL. HIBP documents the shape as website, email and password, and supports searching by the domain of the email address and, separately, by the domain of the website "the info stealer victim was entering credentials into". If that website is your VPN portal or SSO login page, the record is a working credential for your service, not a guess about reuse.
  2. Cookies can carry a live session. Many session tokens are bearer tokens: whoever presents the cookie is the user, and MFA already happened when the session was created. A stolen cookie can therefore get past MFA without the password. NIST SP 800-63B-4 section 5.1 notes that emerging proof-of-possession approaches, such as the device bound session credentials specification, "mitigate the risk of theft of session secrets", and may keep them in protected keystores against malware. Without that kind of binding, a password reset alone does not end a stolen session.
  3. The device is compromised. Anything else that machine could reach, such as SSH keys, cloud CLI credentials or tokens in configuration files, should be presumed taken. The post on secrets in git history covers why an exposed credential has to be rotated, not merely removed.
  4. The device may not be yours. Stealer logs can come from personal machines: a contractor's laptop, a family computer used to check work mail. You cannot reimage it, and your endpoint tooling never saw the infection.

Three dates on one record

Every exposed credential has at least three timestamps, and an alert may show only one.

The gaps change triage. A breach taken years ago and first seen recently may expose a password changed long since, so compare the breach date with the account's last password change: if the change came later, the exposed password is probably stale for that account, though still worth blocking from reuse. A record first seen long ago and alerted today, because you enrolled a domain or the feed back-filled, is not new exposure and should not be counted as new in any metric. A stealer log taken recently and alerted quickly is the case where hours matter, because session cookies expire.

An alert that shows only "detected today" forces you to treat every row as fresh, which turns old combolists into incidents.

From an address to an account

A corpus records addresses. Your response acts on accounts, and only you hold the mapping.

An invented worked example

An alert lists five rows at example.com:

  1. ana@, from a dump of a hobby forum that used slow hashes, breached three years ago. Ana's SSO password changed last month; no local accounts. Confirm MFA and mark reviewed.
  2. ben@, from a combolist, plaintext, first seen two years ago, alerted today because the domain was just enrolled. Ben has a local login on a legacy reporting app with no MFA. Rotate it now and move the app behind SSO.
  3. it-admin@, from a combolist, plaintext. It is the shared login for a vendor support portal. Rotate, split into named accounts, enable MFA.
  4. A contractor's personal address, from a stealer log, with your VPN portal URL and a session cookie for your ticketing system. Incident: revoke sessions, rotate, suspend access until the device is dealt with.
  5. cara@, a leaver, from a breached SaaS vendor. Her identity provider account is disabled, but the vendor's admin console still has her local login. Remove it and audit that vendor's user list.

Five rows, five responses, one incident. A single "force reset for affected users" action handles the first adequately and the rest badly.

What to do, by class

Dump or combolist record:

Stealer-log record, treated as an endpoint incident with credential consequences:

Dark or deep web mention with no credential, such as a forum post offering access to example.com: a lead. Corroborate it against your own logs and the credential records above before acting.

Stop breached passwords being set again

Responding to alerts is the reactive half. The other half is refusing a known-breached password when someone sets or changes it.

SP 800-63B-4 section 3.1.1.2: "When processing a request to establish or change a password, verifiers SHALL compare the prospective secret against a blocklist that contains known commonly used, expected, or compromised passwords. The entire password SHALL be subject to comparison, not substrings or words that might be contained therein." The first example it gives is "Passwords obtained from previous breach corpuses", followed by dictionary words and context-specific words such as the service name or username. A listed password must be rejected with the reason given. SP 800-63B-4 was published in July 2025 and supersedes SP 800-63B as last updated in March 2020.

Two details are easy to miss. NIST frames the blocklist as a defence against online guessing and says "excessively large blocklists are of little incremental security benefit", because rate limiting already bounds online attacks. And it requires verifiers to offer guidance on choosing a strong password, which it calls particularly important after a blocklist rejection because it "discourages trivial modifications of listed weak passwords".

Checking without sending the password

Sending a password, or its unsalted hash, to an external service to check it discloses it. The Pwned Passwords range API avoids this with k-anonymity. As documented, and confirmed with one live request:

  1. Compute the SHA-1 of the candidate password: 40 hexadecimal characters.
  2. Send only the first 5 to https://api.pwnedpasswords.com/range/ followed by the prefix. No API key is needed.
  3. The response lists the remaining 35 characters of every hash in the corpus with that prefix, each followed by a colon and the number of times it was seen. The documentation says every one of the 1,048,576 possible prefixes returns HTTP 200.
  4. Compare locally. If your suffix is listed, the password is in the corpus.

The server learns which bucket you asked about, not which password. The header Add-Padding: true adds dummy entries with a count of 0, so the response size does not reveal the prefix to someone watching encrypted traffic; discard them. The documentation also warns against checking as each character is typed, since successive queries for a growing password can reveal it. Check once, when entry is complete. NTLM suffixes are available through a mode parameter, the corpus can be downloaded for offline checks, and HIBP's email-address range search uses the same design with a 6-character prefix and an API key.

The check belongs in the identity provider's or application's password-set flow, not in a periodic sweep.

When the feed goes quiet

A feed that stops returning data looks exactly like a feed that found nothing. An expired key, an exhausted quota or a changed response format all produce an empty result, which reads as "no exposure". The post on why a passing scan is not a scan that ran covers the general failure. Here, the practical test is whether you can see when each source last returned anything at all, not only when it last returned a match. The same holds for the look-alike domain sources beside it.

Where Maphra fits

Maphra's breach and brand monitoring tracks your domains across breach corpora, reports credential exposure by domain and dark and deep web mentions, alerts on new exposure, and surfaces the accounts that need a reset, by exposed address; mapping each address to the accounts it opens in your estate is the step described above that only you can do. It sits beside asset discovery and exposure analysis, and every finding carries the evidence that produced it.

That is the whole claim. This post does not claim that Maphra parses infostealer logs, distinguishes combolists from single-service dumps, identifies or cracks hash types, reports the three dates separately, searches by website domain, maps addresses to accounts in an identity provider, revokes sessions, or checks passwords at set time. Those are general practice, described so you can apply them with your own identity provider, logs and endpoint tooling, and so you can put the questions below to any feed, ours included.

Questions to ask of any credential-exposure alert or feed

  1. What kind of record is it: a named-service dump, a combolist, a stealer log, or a mention with no credential?
  2. How was the password stored at the source: plaintext, unsalted fast hash, salted slow hash, or unknown?
  3. Which dates do I get: taken, first seen in the corpus, alerted? Which one does "new" mean?
  4. Is it a re-sighting of a pair already reported under another breach name?
  5. For stealer logs, which URL was the credential used on, and were cookies or tokens included?
  6. Is the search by email domain, website domain, or both?
  7. Which accounts does the address map to, including local logins, shared mailboxes, leavers and plus-addressed forms?
  8. Which of those accept a password without SSO, and which enforce MFA?
  9. Has the password changed since the breach date on each mapped account?
  10. Does the response go beyond a reset to session revocation, device remediation and reuse elsewhere?
  11. Do we reject breached passwords at set and change time, without sending the password anywhere?
  12. When did each source last return any data, and would I be told if it stopped?

A credential-exposure alert says that an address and something resembling a secret were found together somewhere. Whether it is an old forum hash, a recycled combolist line or a live session cookie for your VPN, and whose account it opens, decides the response, and each row needs its own answer.

More about Maphra · All posts