Triage dark web credential and card alerts

Grayson triages dark web alerts: whether a leaked password, bank log or card listing matches a customer, whether it still works, and what to do about it.

Grayson triages a dark web or threat intelligence alert against your own records: whether it really refers to this customer, whether someone else can still sign in or pay with what was exposed, and whether to take no action, force a password reset with step-up authentication, reissue the card, or restrict the account until you reach the customer. It reads the vendor's alert, your password-hash and device-token checks, and the customer's sign-ins, devices, payees, payments, card authorizations and contact-center history, and costs about $0.53 to $0.75 per 1,000 alerts.

  • Decides: Match a dark web alert to the customer, judge whether the exposure still works, and choose the response.
  • Call it: When a dark web or threat intelligence vendor sends an alert
  • Questions: 1 yes/no, 1 score, 1 choice
  • Cost: $0.00053 to $0.00075 per decision ($0.53 to $0.75 per 1,000) for these examples' 15,154 to 21,373 input tokens
  • Latency: 220 to 283 ms for these examples, the median of 5 calls each through api.finic.ai from US-West

Examples

Three alerts, each sent with 90 days of the customer's sign-ins (about 85 to 105, with device, address and how each was authenticated), their devices, payees, account activity, recent card authorizations, credential and contact-detail changes, contact-center history and prior alerts. They are a days-old stealer log whose trusted-device cookie someone is already using from proxy addresses, a 2024 bank log reposted for sale long after the bank handled it, and a stealer log from a laptop that is still trusted, where the customer changed his password on that same laptop and a sign-in from a new address may or may not have been him.

Open in Playground

Open in Playground

Open in Playground

A yes/no answer is Grayson's probability that it's true. A choice answer is the top option and Grayson's confidence: 0% when every option is equally likely, 100% when one option has all the probability. A score answer is the expected level, numbering the levels in its criteria from 0, with its confidence measured the same way and, when no level reaches 70%, each level's probability. A multiple-choice answer lists the options at 50% or more.

  • matches_customer filters out misattributed alerts: close alerts below a threshold automatically, and keep the probability with the alert record.
  • still_exposed sets urgency: order the analyst queue by the sum of "Likely" and "Very likely", so live takeovers come first. When the probability sits at both ends, as in the ambiguous example, the answer hinges on one fact (there, whether the new sign-in was the customer), so give it to an analyst to ask.
  • response: automate resets and reissues when the top option is clearly ahead; have an analyst confirm restrictions, which also stop the customer's own payments.

Call it from your code

Save an example as request.json, such as legitimate.json, and send it with your API key in GRAYSON_API_KEY:

curl https://api.finic.ai/v1/decide \
  -H "Authorization: Bearer $GRAYSON_API_KEY" \
  -H "Content-Type: application/json" \
  --data @request.json

The problem

Most dark web alerts need no action: combo lists recirculate old passwords, bank logs get reposted for years, and card data often surfaces after the card was replaced. The few that matter look the same on the vendor's side; the difference is in your records, such as whether the leaked password still matches or someone is signing in with the stolen cookie. Rules keyed on the alert type either reset everyone or miss these cases.

What to send

Send the alert next to the records an analyst would pull, with the secrets removed:

  • The alert. Type, dates, the log's machine details, seller claims and match basis; Grayson needs facts about the secrets, not their values.
  • Your checks on it. Whether the leaked password matches the current one, a previous one or neither; whether the trusted-device token in the log is still active; and, for a screenshot, your ledger at its time (balances that match to the cent prove someone saw the account).
  • Months of sign-ins. Device, address, network and how each sign-in was authenticated. The customer's own routine is what makes a stolen cookie used from a proxy stand out.
  • Changes, payees and scheduled payments. Attempts that stopped at a one-time code show someone is trying; anything that needed no code shows what got through.
  • Account activity and card authorizations. Whether the card is still open, and small declines that suggest the number is being tested.
  • Contact-center history and prior alerts. Callers who can't take a code, and whether this log was already handled.

Add your own policy

How much each kind of alert warrants is a decision fraud teams make in advance, so put your standard in the request. This one handles any for-sale listing of a matched customer's online banking access as an active takeover, whether or not the leaked password still works, because buyers also get the customer's personal details and email access.

Your dark web response standard adds this to the state of the legitimate example:

{
  "institution_policy": "Dark web alert standard (Fraud Operations, revised 2026-08-15). 1. Credential exposures with nothing offered for sale (combo lists, breach dumps, infostealer logs): if the leaked password matches the current or a previous password, force a reset from a device not named in the alert, end all sessions, remove trusted devices and require a one-time code at the next sign-in. 2. Any listing that offers a matched customer's online banking access for sale (a 'bank log') is handled as an active takeover, whether or not the leaked password still works: restrict outbound payments, new payees and contact-detail changes, and keep the restriction until the customer is reached at the phone number on file and confirms the devices they use. Buyers of bank logs get the customer's personal details and email access and use them against the contact center, so a password change alone does not close the case. 3. Card data offered for sale: block and reissue the card if it is still open."
}
QuestionWithoutWith your dark web response standard
matches_customer95% true99% true
still_exposed0.04 of 4, confidence 97%0.13 of 4, confidence 93%
responseno_action, confidence 94%restrict_contact, confidence 62%

The listing in the likely legitimate example matches Priya Raman, so the response moves from no_action to restrict_contact, even though the 2024 password and laptop token stopped working long ago.

Where to call it

  • When the alert arrives, after you've matched it to a candidate customer and run the password-hash comparison, in a background job.
  • Matched and still exposed: run the reset or card reissue automatically, or restrict the account and queue it for outreach; close the rest.
  • Uncertain: send it to an analyst with the probabilities attached.

Cost and latency

ExampleInput tokensPer decisionPer 1,000 decisionsLatency
Obvious20,509$0.00072$0.72283 ms
Legitimate21,373$0.00075$0.75231 ms
Ambiguous15,154$0.00053$0.53220 ms

You pay only for input tokens, at $0.035 per million, and each request is rounded up to the next millionth of a dollar, so a request with a larger state costs proportionally more; every response reports its size in usage.input_tokens. Latency is the median of 5 calls each through api.finic.ai from US-West, and grows with the number of input tokens. Add your own network time to api.finic.ai.

Evaluate on your own data

Score Grayson on your own past cases before you use it: a CSV with one row per case and a column with the right answer to each question. Every other column is sent as the case.

pipx install https://docs.finic.ai/downloads/grayson_cli-0.4.0-py3-none-any.whl
grayson eval my-cases.csv --questions https://docs.finic.ai/recipes/dark-web-alert-triage/questions.json --label matches_customer=<column> --label still_exposed=<column> --label response=<column>

Each --label names the column with that question's right answer:

  • matches_customer: true or false
  • still_exposed: a level, such as "Very likely (over 90%)"
  • response: no_action, reset_step_up, reissue_card, restrict_contact

Or run grayson on its own to set up your questions step by step. You get each question's accuracy and a CSV with Grayson's answer next to yours for every case.

FAQ

Does a password reset fix an infostealer exposure?

Not on its own. A stealer log carries session cookies and remembered-device tokens as well as passwords, so end every session and remove trusted devices too. A new password typed on the infected computer can be captured again, so ask the customer to reset from another device and clean or replace the infected one.

What if an alert could match several customers?

Call once per candidate, each with that customer's records. matches_customer separates the one whose ledger, username and sign-ins fit from the ones that only share a first name and the last four digits of an account number. If no candidate scores high, the listing may be misattributed or belong to another institution.

Should we send the leaked password so Grayson can compare it?

No. Compare it yourself against the stored hash and send the result, as in the examples' credential_check; secrets shouldn't leave the system that needs them. The same goes for screenshots: send the values your vendor extracted, such as names, account endings and balances.

On this page