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 comparison and the customer's sign-ins, devices, profile changes and card status, and costs about $0.07 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.000074 per decision, $0.07 per 1,000, for this example's 2,110 input tokens
  • Latency: 184 ms for this example, the median of 5 calls through api.finic.ai from US-West

Example

A marketplace listing offers a customer's online banking access for $260 with balances that match the ledger and a real leaked password, but the bank has since removed the infected laptop from the trusted devices, the customer has changed the password, and no one else has signed in.

Open in PlaygroundEdit and run this request in the Finic portal.
QuestionGrayson's answer
matches_customerYes, P(yes) over 99%
still_exposedVery unlikely (under 10%), 99%
responseno_action, 93%

Each percentage is Grayson's probability for the answer shown; for a yes/no question it's the probability of yes. 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.
  • 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 request.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, 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. 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, seller claims and match basis; Grayson needs facts about the secrets, not their values.
  • A password-hash comparison result. Whether the leaked password matches the current one, a previous one or neither.
  • Your ledger at the screenshot's time. Balances that match to the cent prove someone saw the account.
  • Sign-ins since the capture date. A hosting-provider sign-in that presents a trusted cookie and skips the code is the infostealer pattern.
  • Profile, payee and security changes. Attempts that stopped at a one-time code show someone is trying.
  • Card status and recent authorizations. Whether the card is still open, and small declines that suggest the number is being tested.

Add your own criteria

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 context:

{
  "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_customerYes, P(yes) over 99%Yes, P(yes) over 99%
still_exposedVery unlikely (under 10%), 99%Very unlikely (under 10%), 96%
responseno_action, 93%restrict_contact, 95%

The listing matches this customer, so the response should move from no action to restrict_contact, even though the leaked password no longer works.

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

This example is 2,110 input tokens, so a decision costs $0.000074: $0.07 per 1,000 decisions, or $74.00 per million. You pay only for input tokens, at $0.035 per million, and each request is rounded up to the next millionth of a dollar. A larger context costs proportionally more; every response reports its size in usage.input_tokens.

Grayson answered this example in 184 ms, the median of 5 calls through api.finic.ai from US-West. Latency 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.2.2-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 this recipe's 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