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
A days-old stealer log with her live password and the desktop's trusted-device cookie. A stealer log from Gloria Benitez's home desktop, captured on October 3, holds her current password, the desktop's trusted-device cookie, her email password and her debit card number. Since then the cookie has signed in three times from proxy addresses with a different browser fingerprint: its Zelle, external-account and email changes stopped at the text code, but it turned off her alerts and scheduled a $2,850 check to a new bill-pay payee. Two callers who couldn't take a code asked us to change her phone number, and her card was tested.
| Question | Grayson's answer |
|---|---|
matches_customer | 99% true |
still_exposed | 3.39 of 4, confidence 69% |
response | restrict_contact, confidence 36% |
20,509 input tokens, $0.00072 per decision, answered in 283 ms.
The request, with long lists cut short. The full request is fraud.json (76 KB).
{
"model": "grayson-1",
"state": {
"case": {
"case_id": "DW-26-001187",
"opened": "2026-10-07T11:58:30Z",
"queue": "Dark web alerts",
"records_as_of": "2026-10-07T12:20:00Z"
},
"customer": {
"customer_id": "cus_41562",
"name": "Gloria Benitez",
"age": 68,
"home": "Tucson, AZ",
"customer_since": "2011-03-22",
"occupation_on_file": "Retired (teacher)",
"online_banking_username": "gbenitez52",
"online_banking_since": "2014-01-08",
"accounts": [
{
"account": "checking x2093",
"opened": "2011-03-22",
"status": "open",
"balance_usd": 19320.81
},
{
"account": "savings x6158",
"opened": "2011-03-22",
"status": "open",
"balance_usd": 39882.85
}
],
"debit_card": {
"card": "x7730",
"on_account": "checking x2093",
"issued": "2025-04-10",
"expires": "04/28",
"status": "active",
"wallets": "none"
},
"phone_on_file": {
"number": "(520) 555-0117",
"line_type": "mobile",
"last_changed": "2018-06-02",
"carrier_sim_change_check": "No SIM change or port-out in 90 days (checked 2026-10-07T12:12Z)"
},
"email_on_file": {
"address": "gbenitez.home@example.net",
"last_changed": "2016-11-30"
},
"address_last_changed": "2011-03-22",
"alert_settings": "Email alerts for transfers over $500 and online card purchases (on since 2019; turned off 2026-10-06, see changes); statement-ready emails",
"travel_notices": "none in 12 months",
"usual_sign_in_addresses": "203.0.113.58 (home cable ISP, Tucson AZ, since 2021) for the desktop and the app; mobile carrier addresses for the app"
},
"sign_in_security": "Online banking uses a username and password. A device becomes trusted after a one-time code sent by SMS to the phone on file, if the customer ticks 'remember this device'; a trusted device (a token stored in a browser cookie) skips the code at sign-in. The mobile app signs in with Face ID or fingerprint after its first code. Codes are also required to add a Zelle recipient or an external transfer account, to change the phone, email or address on file, and to raise transfer limits. Bill-pay payees paid by mailed check, alert settings and statement preferences change without a code. 'Forgot password' emails a reset link to the email on file; a code is required after the reset unless the device is trusted. Changing the password does not end other sessions or remove trusted devices. A sign-in from a new country triggers an SMS 'Was this you?' check. By phone, contact-detail changes need a code to the phone on file or photo ID in a branch.",
"devices": {
"columns": [
"device_id",
"device",
"first_seen",
"trusted_since",
"status",
"last_seen"
],
"rows": [
[
"dv_19f0",
"Windows 7 · Chrome",
"2014-01-08",
"2014-01-08",
"removed 2021-09-14 (replaced)",
"2021-09-10"
],
[
"dv_3a91",
"Windows 10 · Chrome (desktop DESKTOP-GB7H2LQ)",
"2021-09-14",
"2021-09-14",
"trusted",
"2026-10-07T04:02:31Z"
],
[
"dv_51ce",
"Samsung Galaxy A54 · app",
"2023-12-27",
"2023-12-27",
"trusted",
"2026-10-06"
],
[
"dv_8e07",
"Windows 10 · Firefox 130",
"2026-10-05",
"",
"not trusted",
"2026-10-05"
]
]
},
"credential_and_contact_changes": {
"columns": [
"ts",
"change",
"channel",
"device_id",
"ip",
"verification"
],
"rows": [
[
"2014-01-08T17:20:00Z",
"Online banking enrolled",
"branch",
"",
"",
"photo ID"
],
[
"2016-11-30T18:02:11Z",
"Email on file changed",
"web",
"dv_19f0",
"203.0.113.58",
"SMS code"
],
[
"2018-06-02T16:45:09Z",
"Phone on file changed (new mobile number)",
"branch",
"",
"",
"photo ID"
],
[
"2021-09-14T15:10:37Z",
"Device trusted: dv_3a91",
"web",
"dv_3a91",
"203.0.113.58",
"SMS code"
],
[
"2022-05-03T16:33:50Z",
"Password changed",
"web",
"dv_3a91",
"203.0.113.58",
"current password"
],
"… 4 more in fraud.json"
]
},
"payees": {
"pending_or_abandoned_since_2026_10_01": [
"Zelle recipient 'Devon Marsh' (602) 555-0148: started 2026-10-04T10:50Z from dv_3a91 at 198.51.100.23; code not entered",
"External transfer account at another bank ending 6620: started 2026-10-06T10:09Z from dv_3a91 at 198.51.100.141; code not entered"
],
"columns": [
"payee",
"type",
"added",
"added_from",
"verification",
"payments_last_90_days",
"last_paid"
],
"rows": [
[
"Tucson Electric Power",
"bill pay",
"2014-02-11",
"web",
"none required",
3,
"2026-09-12"
],
[
"City of Tucson Water",
"bill pay",
"2014-02-11",
"web",
"none required",
3,
"2026-09-17"
],
[
"St Ambrose Parish",
"bill pay",
"2015-06-01",
"web",
"none required",
3,
"2026-09-05"
],
[
"Banner Health patient account",
"bill pay",
"2025-02-19",
"web",
"none required",
1,
"2026-07-31"
],
[
"Tucson Orthopaedic Institute",
"bill pay",
"2026-03-04",
"web",
"none required",
1,
"2026-09-10"
],
[
"Sofia Benitez (granddaughter per customer)",
"Zelle",
"2022-12-20",
"web",
"SMS code",
3,
"2026-09-25"
],
[
"D Marsh Home Repair (paper check to Phoenix, AZ)",
"bill pay",
"2026-10-07",
"web, dv_3a91 at 198.51.100.23",
"none required",
0,
""
]
]
},
"scheduled_payments": {
"columns": [
"scheduled",
"payee",
"amount_usd",
"send_on",
"method",
"set_up_from",
"status"
],
"rows": [
[
"2025-02-19T17:02:10Z",
"Tucson Electric Power",
"statement balance",
"2026-10-12",
"electronic",
"dv_3a91 at 203.0.113.58",
"recurring monthly"
],
[
"2014-02-11T18:30:00Z",
"City of Tucson Water",
"statement balance",
"2026-10-17",
"electronic",
"dv_19f0",
"recurring monthly"
],
[
"2026-10-07T04:05:48Z",
"D Marsh Home Repair",
2850,
"2026-10-08",
"paper check mailed by our bill-pay processor",
"dv_3a91 at 198.51.100.23",
"scheduled; can be cancelled until 2026-10-08T14:00Z"
]
]
},
"sign_in_history": {
"period": "2026-07-09 to 2026-10-07T12:20Z, all channels",
"columns": [
"ts",
"device_id",
"ip",
"ip_info",
"method",
"… 4 more in fraud.json"
],
"rows": [
[
"2026-07-09T15:54:03Z",
"dv_3a91",
"203.0.113.58",
"Residential cable ISP, Tucson AZ",
"password + trusted device",
"… 4 more in fraud.json"
],
[
"2026-07-10T03:55:50Z",
"dv_51ce",
"192.0.2.118",
"Mobile carrier, AZ",
"fingerprint (app)",
"… 4 more in fraud.json"
],
[
"2026-07-12T21:37:48Z",
"dv_51ce",
"203.0.113.58",
"Residential cable ISP, Tucson AZ",
"fingerprint (app)",
"… 4 more in fraud.json"
],
[
"2026-07-13T15:04:17Z",
"dv_3a91",
"203.0.113.58",
"Residential cable ISP, Tucson AZ",
"password + trusted device",
"… 4 more in fraud.json"
],
[
"2026-07-13T22:54:32Z",
"dv_51ce",
"203.0.113.58",
"Residential cable ISP, Tucson AZ",
"fingerprint (app)",
"… 4 more in fraud.json"
],
"… 96 more in fraud.json"
]
},
"security_messages": {
"period": "2026-07-09 to 2026-10-07",
"columns": [
"ts",
"channel",
"to",
"message",
"outcome"
],
"rows": [
[
"2026-07-21T13:00:00Z",
"email",
"gbenitez.home@example.net",
"Your statement is ready",
"sent"
],
[
"2026-08-06T15:31:00Z",
"email",
"gbenitez.home@example.net",
"Mobile deposit received: $120.00",
"sent"
],
[
"2026-08-22T13:00:00Z",
"email",
"gbenitez.home@example.net",
"Your statement is ready",
"sent"
],
[
"2026-09-21T13:00:00Z",
"email",
"gbenitez.home@example.net",
"Your statement is ready",
"sent"
],
[
"2026-10-04T10:51:02Z",
"SMS",
"(520) 555-0117",
"Code to add a Zelle recipient. We will never call you to ask for it.",
"not entered; expired after 10 min"
],
"… 8 more in fraud.json"
]
},
"account_activity": {
"period": "posted 2026-07-09 to 2026-10-07",
"columns": [
"posted",
"account",
"type",
"description",
"amount_usd"
],
"rows": [
[
"2026-07-09",
"checking x2093",
"ACH debit",
"T-MOBILE AUTOPAY",
-65
],
[
"2026-07-10",
"checking x2093",
"debit card x7730",
"WALGREENS #3521 TUCSON AZ",
-23.12
],
[
"2026-07-11",
"checking x2093",
"debit card x7730",
"FRYS FOOD #0673 TUCSON AZ",
-65.12
],
[
"2026-07-11",
"checking x2093",
"debit card x7730",
"SPROUTS FARMERS MKT #142 TUCSON AZ",
-52.67
],
[
"2026-07-12",
"checking x2093",
"bill pay",
"TUCSON ELECTRIC POWER (bill pay)",
-139.01
],
"… 157 more in fraud.json"
]
},
"card_authorizations": {
"card": "debit x7730",
"period": "2026-09-16 to 2026-10-07, approvals and declines",
"columns": [
"ts",
"merchant",
"mcc",
"entry",
"amount_usd",
"result",
"avs",
"cvv2"
],
"rows": [
[
"2026-09-16T00:22:19Z",
"SPROUTS FARMERS MKT #142 TUCSON AZ",
"5411",
"chip (05)",
28.88,
"approved (00)",
"",
""
],
[
"2026-09-16T18:07:35Z",
"MICHAELS #4521 TUCSON AZ",
"5945",
"contactless (07)",
47.29,
"approved (00)",
"",
""
],
[
"2026-09-18T17:18:23Z",
"FRYS FOOD #0673 TUCSON AZ",
"5411",
"contactless (07)",
42.33,
"approved (00)",
"",
""
],
[
"2026-09-18T23:46:55Z",
"WALGREENS #3521 TUCSON AZ",
"5912",
"chip (05)",
25.12,
"approved (00)",
"",
""
],
[
"2026-09-19T00:49:40Z",
"SPROUTS FARMERS MKT #142 TUCSON AZ",
"5411",
"chip (05)",
37.97,
"approved (00)",
"",
""
],
"… 19 more in fraud.json"
]
},
"contact_center_history": {
"period": "last 12 months",
"columns": [
"ts",
"channel",
"caller",
"verification",
"reason",
"outcome"
],
"rows": [
[
"2026-01-14T17:41:00Z",
"phone",
"(520) 555-0117 (on file)",
"SMS code",
"Asked for her 1099-INT",
"Mailed copy"
],
[
"2026-06-02T16:05:00Z",
"phone",
"(520) 555-0117 (on file)",
"SMS code",
"Ordered checks",
"Order placed"
],
[
"2026-10-05T18:05:00Z",
"phone",
"(520) 555-0131 (not on file; carrier lookup: non-fixed VoIP)",
"Name, date of birth, home address and email on file answered; last 4 of SSN not given ('doesn't have her card'); declined the code to the phone on file ('my phone is broken, that's why I'm calling')",
"Caller said she was Gloria Benitez; asked to change the phone on file to (520) 555-0131 and to stop the text codes; then asked for the balance and recent large transactions",
"Declined per procedure (needs a code or photo ID in a branch). Agent referral FR-26-04417 to Fraud Operations: 'could not verify'"
],
[
"2026-10-06T20:15:00Z",
"phone",
"(520) 555-0189 (not on file; carrier lookup: non-fixed VoIP)",
"Name, date of birth, home address, email on file and last 4 of SSN answered correctly; declined the code to the phone on file ('my phone was stolen')",
"Caller said she was Gloria Benitez; asked to replace the phone on file with (520) 555-0189 and to send a replacement debit card to a new mailing address ('staying with my daughter in Phoenix')",
"Declined per procedure. Caller said she would 'come to a branch tomorrow with my ID'. Agent added the call to referral FR-26-04417. Referral status: queued, not yet reviewed"
]
]
},
"prior_alerts": [
{
"alert_id": "TI-20230612-1150",
"received": "2023-06-12T14:20:00Z",
"type": "Email address in a combo list (email and password pairs)",
"detail": "Email on file paired with a password; our hash comparison matched neither the current nor any previous password",
"disposition": "Closed, no action"
}
],
"alert": {
"alert_id": "TI-20261007-0233",
"received": "2026-10-07T11:58:00Z",
"vendor_feed": "Threat intelligence vendor: compromised credentials from infostealer logs",
"vendor_severity": "critical (log contains our bank's login and cookies)",
"where_seen": "An automated log shop on Tor ($12 per log) and a private Telegram channel that reposts logs",
"first_seen_by_vendor": "2026-10-05T06:12:00Z",
"log": {
"log_id": "a91c4e07f2",
"malware": "Commodity infostealer sold as a service (vendor family code IS-114)",
"captured": "2026-10-03T01:12:44Z",
"computer_name": "DESKTOP-GB7H2LQ",
"windows_user": "Gloria",
"os": "Windows 10 Home 22H2",
"browser": "Chrome 129",
"ip_at_capture": "203.0.113.58",
"timezone": "UTC-07:00 Arizona",
"screen": "1920x1080",
"antivirus": "Windows Defender",
"launched_file": "C:\\Users\\Gloria\\Downloads\\Delivery_Notice_7781.pdf.exe",
"sites_with_saved_passwords": 46,
"cookies": 1288,
"screenshot": "Desktop with an email inbox open; no account numbers or balances visible"
},
"entries_for_our_bank": {
"login_url": "https://online.ourbank.example/login",
"username": "gbenitez52",
"password": "present (compared with our stored hashes, see alert_checks)",
"cookies": [
{
"name": "tdt",
"what": "trusted-device token",
"expires": "2027-03-14"
},
{
"name": "sid",
"what": "session",
"expires": "2026-10-03T01:42:00Z"
},
{
"name": "lang",
"what": "language preference",
"expires": "2027-10-02"
},
{
"name": "_ga",
"what": "analytics",
"expires": "2027-11-06"
}
]
},
"other_entries_of_note": [
"Password and session cookies for the webmail account gbenitez.home@example.net (the email on file)",
"Username and password for the online account at the mobile carrier of the phone on file",
"Browser autofill: full name, home address, phone number, date of birth",
"Saved card: debit card ending 7730, expiry 04/28, name on card; no security code"
],
"vendor_match": {
"matched_on": [
"online banking username",
"email on file",
"home address in autofill"
],
"vendor_confidence": "high"
}
},
"alert_checks": {
"credential_check": {
"method": "Password from the log hashed with this login's salt and algorithm and compared with the current and previous hashes; plaintext discarded, never logged",
"matches_current_password": true,
"matches_a_previous_password": false,
"current_password_set": "2024-08-11T16:22:05Z"
},
"device_token_check": {
"token_in_log": "tdt for dv_3a91 (the desktop, trusted since 2021-09-14)",
"token_status": "active",
"presented_since_capture": "7 successful sign-ins: 4 from 203.0.113.58 with matching fingerprint; 3 from 198.51.100.23 or 198.51.100.141 with a different fingerprint"
},
"log_machine_vs_our_records": "Computer name, screen size, timezone and capture IP match dv_3a91 and the customer's usual address",
"balance_check": "Not applicable: the log's screenshot shows no balances"
}
},
"questions": {
"matches_customer": {
"type": "noul",
"instructions": "Does the vendor's alert refer to this customer's own login, account or card at our bank (including a card since closed or replaced), rather than to a different person?"
},
"still_exposed": {
"type": "score",
"instructions": "How likely is it that someone other than the customer can currently use the exposed data to sign in to this customer's online banking or make payments from the customer's accounts or cards?",
"criteria": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"response": {
"type": "choice",
"instructions": "What should the bank do about this alert for this customer?",
"criteria": {
"no_action": "Log the alert and take no action: it doesn't match this customer, or nothing it exposes still works",
"reset_step_up": "Force a password 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",
"reissue_card": "Block the exposed card and issue a new card number; online banking access needs no change",
"restrict_contact": "Restrict outbound payments, new payees and contact-detail changes until the customer is reached at the phone number on file"
}
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_ea07b09a4ccc49a6b66497c7c025daf9",
"model": "grayson-1",
"answers": {
"matches_customer": {
"type": "noul",
"noul": 0.9941
},
"still_exposed": {
"type": "score",
"score": 3.394,
"legend": {
"0": "Very unlikely (under 10%)",
"1": "Unlikely (10-40%)",
"2": "Uncertain (40-60%)",
"3": "Likely (60-90%)",
"4": "Very likely (over 90%)"
},
"confidence": 0.6906,
"probabilities": {
"0": 0.0899,
"1": 0.0331,
"2": 0.0227,
"3": 0.1018,
"4": 0.7525
}
},
"response": {
"type": "choice",
"choice": "restrict_contact",
"confidence": 0.3566,
"probabilities": {
"no_action": 0.0122,
"reset_step_up": 0.4566,
"reissue_card": 0.0138,
"restrict_contact": 0.5174
}
}
},
"usage": {
"input_tokens": 20509,
"output_tokens": 0
}
}Open in Playground
A 2024 bank log reposted for sale after the laptop was removed and the password changed. A new seller lists Priya Raman's online banking for $45, but the screenshot's balances match our ledger in March 2024, and the linked stealer log is the one we handled in April 2024: that laptop was removed, its token revoked, and the password has changed three times since. Her recent trip to Lisbon, a new iPad and two mistyped passwords are all her own.
| Question | Grayson's answer |
|---|---|
matches_customer | 95% true |
still_exposed | 0.04 of 4, confidence 97% |
response | no_action, confidence 94% |
21,373 input tokens, $0.00075 per decision, answered in 231 ms.
The request, with long lists cut short. The full request is legitimate.json (79 KB).
{
"model": "grayson-1",
"state": {
"case": {
"case_id": "DW-26-001162",
"opened": "2026-10-06T13:40:20Z",
"queue": "Dark web alerts",
"records_as_of": "2026-10-06T14:05:00Z"
},
"customer": {
"customer_id": "cus_30915",
"name": "Priya Raman",
"age": 36,
"home": "Raleigh, NC",
"customer_since": "2017-08-14",
"occupation_on_file": "Software quality engineer",
"online_banking_username": "praman_nc",
"online_banking_since": "2017-08-14",
"accounts": [
{
"account": "checking x8834",
"opened": "2017-08-14",
"status": "open",
"balance_usd": 9663.37
},
{
"account": "savings x2290",
"opened": "2019-01-07",
"status": "open",
"balance_usd": 14484.97
}
],
"debit_card": {
"card": "x4471",
"on_account": "checking x8834",
"issued": "2025-11-03 (renewal at expiry)",
"expires": "11/29",
"status": "active",
"wallets": "none"
},
"phone_on_file": {
"number": "(919) 555-0164",
"line_type": "mobile",
"last_changed": "2017-08-14",
"carrier_sim_change_check": "No SIM change or port-out in 90 days (checked 2026-10-06T13:52Z)"
},
"email_on_file": {
"address": "priya.raman@example.com",
"last_changed": "2019-05-20"
},
"address_last_changed": "2025-02-03",
"alert_settings": "Email alerts for new devices and for transfers over $250; SMS card decline alerts",
"travel_notices": "Portugal, 2026-09-12 to 2026-09-20",
"usual_sign_in_addresses": "203.0.113.164 (home fiber ISP, Raleigh NC, since 2025-02) for all devices; mobile carrier addresses for the app"
},
"sign_in_security": "Online banking uses a username and password. A device becomes trusted after a one-time code sent by SMS to the phone on file, if the customer ticks 'remember this device'; a trusted device (a token stored in a browser cookie) skips the code at sign-in. The mobile app signs in with Face ID or fingerprint after its first code. Codes are also required to add a Zelle recipient or an external transfer account, to change the phone, email or address on file, and to raise transfer limits. Bill-pay payees paid by mailed check, alert settings and statement preferences change without a code. 'Forgot password' emails a reset link to the email on file; a code is required after the reset unless the device is trusted. Changing the password does not end other sessions or remove trusted devices. A sign-in from a new country triggers an SMS 'Was this you?' check. By phone, contact-detail changes need a code to the phone on file or photo ID in a branch.",
"devices": {
"columns": [
"device_id",
"device",
"first_seen",
"trusted_since",
"status",
"last_seen"
],
"rows": [
[
"dv_6b02",
"Windows 10 · Edge (laptop LAPTOP-PR5T8Q)",
"2021-02-11",
"2021-02-11",
"removed 2024-04-09 (dark web alert TI-20240409-0087)",
"2024-04-08"
],
[
"dv_a20e",
"iPhone 15 Pro · app",
"2023-10-07",
"2023-10-07",
"trusted",
"2026-10-06"
],
[
"dv_c7d4",
"MacBook Air · Safari",
"2024-05-02",
"2024-05-02",
"trusted",
"2026-10-04"
],
[
"dv_e913",
"iPad (10th gen) · Safari",
"2026-09-29",
"2026-09-29",
"trusted",
"2026-10-06"
]
]
},
"credential_and_contact_changes": {
"columns": [
"ts",
"change",
"channel",
"device_id",
"ip",
"verification"
],
"rows": [
[
"2017-08-14T15:30:00Z",
"Online banking enrolled",
"branch",
"",
"",
"photo ID"
],
[
"2019-05-20T23:12:48Z",
"Email on file changed",
"web",
"",
"",
"SMS code"
],
[
"2021-02-11T01:04:33Z",
"Device trusted: dv_6b02",
"web",
"dv_6b02",
"",
"SMS code"
],
[
"2023-10-07T18:22:10Z",
"Device trusted: dv_a20e (app)",
"app",
"dv_a20e",
"",
"SMS code"
],
[
"2024-04-09T15:02:00Z",
"Analyst action on TI-20240409-0087: all sessions ended, dv_6b02 removed, password reset required",
"staff",
"",
"",
""
],
"… 6 more in legitimate.json"
]
},
"payees": {
"columns": [
"payee",
"type",
"added",
"added_from",
"verification",
"payments_last_90_days",
"last_paid"
],
"rows": [
[
"Duke Energy Progress",
"bill pay",
"2025-02-05",
"web",
"none required",
3,
"2026-09-08"
],
[
"WakeMed Physician Practices",
"bill pay",
"2026-08-19",
"web",
"none required",
1,
"2026-08-19"
],
[
"Maya Chen",
"Zelle",
"2023-03-11",
"app",
"SMS code",
1,
"2026-07-26"
],
[
"Ananya Raman",
"Zelle",
"2026-09-01",
"app",
"SMS code",
1,
"2026-09-01"
]
]
},
"sign_in_history": {
"period": "2026-07-08 to 2026-10-06T14:05Z, all channels",
"columns": [
"ts",
"device_id",
"ip",
"ip_info",
"method",
"… 4 more in legitimate.json"
],
"rows": [
[
"2026-07-09T00:02:42Z",
"dv_a20e",
"203.0.113.164",
"Residential fiber ISP, Raleigh NC",
"Face ID (app)",
"… 4 more in legitimate.json"
],
[
"2026-07-09T11:26:33Z",
"dv_a20e",
"203.0.113.164",
"Residential fiber ISP, Raleigh NC",
"Face ID (app)",
"… 4 more in legitimate.json"
],
[
"2026-07-10T23:18:52Z",
"dv_c7d4",
"203.0.113.164",
"Residential fiber ISP, Raleigh NC",
"password + trusted device",
"… 4 more in legitimate.json"
],
[
"2026-07-11T00:16:54Z",
"dv_a20e",
"203.0.113.164",
"Residential fiber ISP, Raleigh NC",
"Face ID (app)",
"… 4 more in legitimate.json"
],
[
"2026-07-11T12:34:31Z",
"dv_a20e",
"203.0.113.164",
"Residential fiber ISP, Raleigh NC",
"Face ID (app)",
"… 4 more in legitimate.json"
],
"… 99 more in legitimate.json"
]
},
"security_messages": {
"period": "2026-07-08 to 2026-10-06",
"columns": [
"ts",
"channel",
"to",
"message",
"outcome"
],
"rows": [
[
"2026-07-09T10:00:00Z",
"email",
"priya.raman@example.com",
"Your statement is ready",
"sent"
],
[
"2026-07-22T12:04:00Z",
"email",
"priya.raman@example.com",
"Password reset link",
"link opened 2026-07-22T12:05Z from dv_c7d4"
],
[
"2026-07-22T12:05:00Z",
"SMS",
"(919) 555-0164",
"Code to finish your password reset",
"entered"
],
[
"2026-07-22T12:06:00Z",
"email",
"priya.raman@example.com",
"Your password was changed",
"sent"
],
[
"2026-08-09T10:00:00Z",
"email",
"priya.raman@example.com",
"Your statement is ready",
"sent"
],
"… 7 more in legitimate.json"
]
},
"account_activity": {
"period": "posted 2026-07-08 to 2026-10-05",
"columns": [
"posted",
"account",
"type",
"description",
"amount_usd"
],
"rows": [
[
"2026-07-08",
"checking x8834",
"bill pay",
"DUKE ENERGY PROGRESS (bill pay)",
-113.59
],
[
"2026-07-09",
"checking x8834",
"debit card x4471",
"BURNT OAK BREWING RALEIGH NC",
-47.94
],
[
"2026-07-09",
"checking x8834",
"debit card x4471",
"HARRIS TEETER #0119 RALEIGH NC",
-76.16
],
[
"2026-07-10",
"checking x8834",
"ACH credit",
"LINDQVIST SOFTWARE PAYROLL PPD",
2846.19
],
[
"2026-07-10",
"checking x8834",
"debit card x4471",
"HARRIS TEETER #0119 RALEIGH NC",
-90.6
],
"… 176 more in legitimate.json"
]
},
"card_authorizations": {
"card": "debit x4471",
"period": "2026-09-15 to 2026-10-06, approvals and declines",
"columns": [
"ts",
"merchant",
"mcc",
"entry",
"amount_usd",
"result",
"avs",
"cvv2"
],
"rows": [
[
"2026-09-15T10:05:00Z",
"MUSEU CALOUSTE GULBENKIAN LISBOA PRT",
"7991",
"contactless (07)",
21.8,
"approved (00)",
"",
""
],
[
"2026-09-15T14:20:00Z",
"METRO LISBOA PRT",
"4111",
"contactless (07)",
7.4,
"approved (00)",
"",
""
],
[
"2026-09-16T14:23:46Z",
"PASTELARIA ALFAMA LISBOA PRT",
"5814",
"contactless (07)",
4.98,
"approved (00)",
"",
""
],
[
"2026-09-16T19:36:31Z",
"UBER *TRIP LISBOA PRT",
"4121",
"card on file (10)",
10.01,
"approved (00)",
"",
""
],
[
"2026-09-17T10:29:54Z",
"UBER *TRIP LISBOA PRT",
"4121",
"card on file (10)",
13.6,
"approved (00)",
"",
""
],
"… 31 more in legitimate.json"
]
},
"contact_center_history": {
"period": "since 2024-01-01",
"columns": [
"ts",
"channel",
"caller",
"verification",
"reason",
"outcome"
],
"rows": [
[
"2024-04-09T15:20:00Z",
"phone (outbound)",
"(919) 555-0164 (on file)",
"SMS code",
"Outreach for dark web alert TI-20240409-0087",
"Customer said she had installed a free PDF converter on the laptop in March; agreed to stop using it; reset password from her phone; said she would change her email password"
],
[
"2025-02-03T17:00:00Z",
"branch",
"in person",
"photo ID",
"Address change",
"Done"
],
[
"2026-09-21T14:12:00Z",
"chat (app)",
"dv_a20e",
"signed-in app session",
"Asked why her card was declined at a Lisbon restaurant on 9/17",
"Explained that the tap needed her PIN under European rules; the chip-and-PIN retry was approved. No changes"
]
]
},
"prior_alerts": [
{
"alert_id": "TI-20240409-0087",
"received": "2024-04-09T13:31:00Z",
"type": "Infostealer log with our bank's login",
"detail": "Log captured 2024-03-15T00:05Z on LAPTOP-PR5T8Q (dv_6b02); password matched the then-current password; trusted-device cookie for dv_6b02",
"disposition": "Password reset forced, sessions ended, dv_6b02 removed; customer reached 2024-04-09; no unauthorized activity found; closed"
},
{
"alert_id": "TI-20250916-0412",
"received": "2025-09-16T15:02:00Z",
"type": "Email address in a breach dump (online retailer breach, 2025)",
"detail": "Email on file with a password hash from the retailer; not comparable with ours, and the username for our bank is not the email",
"disposition": "Closed, no action"
}
],
"alert": {
"alert_id": "TI-20261006-0098",
"received": "2026-10-06T13:40:00Z",
"vendor_feed": "Threat intelligence vendor: marketplace monitoring, bank access listings ('bank logs')",
"vendor_severity": "high (listing names our bank)",
"listing": {
"posted": "2026-10-05T22:18:00Z",
"venue": "Invite-only marketplace on Tor",
"seller": {
"first_seen_by_vendor": "2026-08",
"listings_seen_by_vendor": 19,
"marketplace_rating": "no ratings yet",
"vendor_note_on_seller": "6 of the seller's 19 listings reuse screenshots the vendor first saw on another forum in 2024"
},
"title": "[OUR BANK] chk + sav | bal 6k | cookies | full info | checked 10/03",
"price_usd": 45,
"seller_claims": [
"Online banking login and password",
"Browser cookies",
"Holder's full name, date of birth, address and SSN",
"Email account access",
"Checked valid 10/03"
],
"screenshot_extract": {
"method": "Vendor text extraction from the seller's screenshot",
"name_shown": "Priya R.",
"accounts_shown": [
{
"type": "checking",
"last4": "8834",
"balance_usd": 6118.42
},
{
"type": "savings",
"last4": "2290",
"balance_usd": 3050
}
],
"clock_shown": "Mar 14, 8:02 PM (no year)",
"browser_shown": "Edge on Windows"
}
},
"linked_credential_record": {
"source": "Infostealer log the vendor ties to this listing by machine name and screenshot",
"captured": "2024-03-15T00:05:00Z",
"first_seen_by_vendor": "2024-04-06",
"computer_name": "LAPTOP-PR5T8Q",
"os": "Windows 10 Home",
"browser": "Edge 122",
"ip_at_capture": "198.51.100.37 (residential cable ISP, Raleigh NC)",
"entries_for_our_bank": "Username praman_nc, a password, and 3 cookies for online.ourbank.example (trusted-device token for dv_6b02, an expired session, language)",
"other_entries_of_note": "Password for priya.raman@example.com; browser autofill with name, address and date of birth"
},
"vendor_match": {
"matched_on": [
"online banking username",
"account last four 8834 and 2290",
"first name and last initial"
],
"vendor_confidence": "high"
}
},
"alert_checks": {
"credential_check": {
"method": "Password from the log hashed with this login's salt and algorithm and compared with the current and previous hashes; plaintext discarded, never logged",
"matches_current_password": false,
"matches_a_previous_password": true,
"which_previous_password": "The one replaced on 2024-04-09 by the forced reset",
"password_changes_since_capture": 3,
"current_password_set": "2026-07-22T12:05:40Z"
},
"device_token_check": {
"token_in_log": "Trusted-device token for dv_6b02",
"token_status": "revoked 2024-04-09 when dv_6b02 was removed",
"presented_since_capture": "Never presented after 2024-04-08"
},
"log_machine_vs_our_records": "LAPTOP-PR5T8Q matches dv_6b02 (removed 2024-04-09); no Windows device has signed in since 2024-04-08",
"balance_check": {
"screenshot_clock": "Mar 14, 8:02 PM, no year; local time in Raleigh",
"ledger_at_that_clock_time": [
{
"as_of": "2026-03-15T00:02:00Z",
"checking_8834": 11402.9,
"savings_2290": 9800,
"matches_screenshot": false
},
{
"as_of": "2025-03-15T00:02:00Z",
"checking_8834": 4870.13,
"savings_2290": 6300,
"matches_screenshot": false
},
{
"as_of": "2024-03-15T00:02:00Z",
"checking_8834": 6118.42,
"savings_2290": 3050,
"matches_screenshot": true
}
]
},
"sign_ins_around_seller_check_date": "2026-10-02 to 2026-10-04 (Raleigh time): 5 successful sign-ins, all from dv_a20e, dv_e913 at 203.0.113.164; 2 failed attempts, all on dv_e913 at 203.0.113.164; no sign-in or attempt from any other device"
}
},
"questions": {
"matches_customer": {
"type": "noul",
"instructions": "Does the vendor's alert refer to this customer's own login, account or card at our bank (including a card since closed or replaced), rather than to a different person?"
},
"still_exposed": {
"type": "score",
"instructions": "How likely is it that someone other than the customer can currently use the exposed data to sign in to this customer's online banking or make payments from the customer's accounts or cards?",
"criteria": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"response": {
"type": "choice",
"instructions": "What should the bank do about this alert for this customer?",
"criteria": {
"no_action": "Log the alert and take no action: it doesn't match this customer, or nothing it exposes still works",
"reset_step_up": "Force a password 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",
"reissue_card": "Block the exposed card and issue a new card number; online banking access needs no change",
"restrict_contact": "Restrict outbound payments, new payees and contact-detail changes until the customer is reached at the phone number on file"
}
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_29b125bec0dc4930a2659b855f1f8eb6",
"model": "grayson-1",
"answers": {
"matches_customer": {
"type": "noul",
"noul": 0.9466
},
"still_exposed": {
"type": "score",
"score": 0.045,
"legend": {
"0": "Very unlikely (under 10%)",
"1": "Unlikely (10-40%)",
"2": "Uncertain (40-60%)",
"3": "Likely (60-90%)",
"4": "Very likely (over 90%)"
},
"confidence": 0.9711,
"probabilities": {
"0": 0.9769,
"1": 0.0139,
"2": 0.0019,
"3": 0.0021,
"4": 0.0051
}
},
"response": {
"type": "choice",
"choice": "no_action",
"confidence": 0.937,
"probabilities": {
"no_action": 0.9527,
"reset_step_up": 0.0369,
"reissue_card": 0.001,
"restrict_contact": 0.0093
}
}
},
"usage": {
"input_tokens": 21373,
"output_tokens": 0
}
}Open in Playground
A password changed on the infected laptop, then a sign-in from a new Columbus address. A stealer log from Marcus Okafor's laptop went on sale on October 4. He had already changed his password, but on that same laptop, which is still trusted and may still be infected (this malware re-runs daily until removed). On October 6 the laptop's token and the new password signed in from a Columbus address we had never seen, read statements and contact details and moved nothing: him away from home, or a buyer who has the new password.
| Question | Grayson's answer |
|---|---|
matches_customer | 99% true |
still_exposed | 2.13 of 4, confidence 19% (Very unlikely 31%, Unlikely 11%, Uncertain 6%, Likely 17%, Very likely 35%) |
response | reset_step_up, confidence 83% |
15,154 input tokens, $0.00053 per decision, answered in 220 ms.
The request, with long lists cut short. The full request is ambiguous.json (58 KB).
{
"model": "grayson-1",
"state": {
"case": {
"case_id": "DW-26-001203",
"opened": "2026-10-08T14:22:40Z",
"queue": "Dark web alerts",
"records_as_of": "2026-10-08T14:45:00Z"
},
"customer": {
"customer_id": "cus_52208",
"name": "Marcus Okafor",
"age": 41,
"home": "Columbus, OH",
"customer_since": "2016-04-02",
"occupation_on_file": "Registered nurse",
"online_banking_username": "mokafor_614",
"online_banking_since": "2016-04-02",
"accounts": [
{
"account": "checking x5520",
"opened": "2016-04-02",
"status": "open",
"balance_usd": 8972.45
},
{
"account": "savings x7713",
"opened": "2018-09-14",
"status": "open",
"balance_usd": 10190.41
}
],
"debit_card": {
"card": "x3861",
"on_account": "checking x5520",
"issued": "2024-06-20",
"expires": "06/28",
"status": "active",
"wallets": "none"
},
"phone_on_file": {
"number": "(614) 555-0172",
"line_type": "mobile",
"last_changed": "2016-04-02",
"carrier_sim_change_check": "No SIM change or port-out in 90 days (checked 2026-10-08T14:31Z)"
},
"email_on_file": {
"address": "marcus.okafor@example.net",
"last_changed": "2016-04-02"
},
"address_last_changed": "2022-06-30",
"alert_settings": "Email alerts for sign-ins from new devices (turned on 2026-10-01 during a call); statement-ready emails",
"travel_notices": "none in 12 months",
"usual_sign_in_addresses": "203.0.113.77 (home cable ISP, Columbus OH, since 2022) for both devices; 198.51.100.140 (another Columbus cable address, first seen 2025-11, about monthly) for the laptop; mobile carrier addresses for the app"
},
"sign_in_security": "Online banking uses a username and password. A device becomes trusted after a one-time code sent by SMS to the phone on file, if the customer ticks 'remember this device'; a trusted device (a token stored in a browser cookie) skips the code at sign-in. The mobile app signs in with Face ID or fingerprint after its first code. Codes are also required to add a Zelle recipient or an external transfer account, to change the phone, email or address on file, and to raise transfer limits. Bill-pay payees paid by mailed check, alert settings and statement preferences change without a code. 'Forgot password' emails a reset link to the email on file; a code is required after the reset unless the device is trusted. Changing the password does not end other sessions or remove trusted devices. A sign-in from a new country triggers an SMS 'Was this you?' check. By phone, contact-detail changes need a code to the phone on file or photo ID in a branch.",
"devices": {
"columns": [
"device_id",
"device",
"first_seen",
"trusted_since",
"status",
"last_seen"
],
"rows": [
[
"dv_2d10",
"Pixel 6 · app",
"2021-12-26",
"2021-12-26",
"removed 2024-11-03 (phone replaced)",
"2024-11-02"
],
[
"dv_7c22",
"Windows 11 · Chrome (laptop LAPTOP-MO4K21)",
"2024-01-12",
"2024-01-12",
"trusted",
"2026-10-08"
],
[
"dv_4e8b",
"Pixel 8 · app",
"2024-11-03",
"2024-11-03",
"trusted",
"2026-10-08"
]
]
},
"credential_and_contact_changes": {
"columns": [
"ts",
"change",
"channel",
"device_id",
"ip",
"verification"
],
"rows": [
[
"2016-04-02T16:00:00Z",
"Online banking enrolled",
"branch",
"",
"",
"photo ID"
],
[
"2021-12-26T20:14:09Z",
"Device trusted: dv_2d10 (app)",
"app",
"dv_2d10",
"",
"SMS code"
],
[
"2022-06-30T15:30:00Z",
"Address on file changed (bought condo)",
"branch",
"",
"",
"photo ID"
],
[
"2024-01-12T02:41:27Z",
"Device trusted: dv_7c22",
"web",
"dv_7c22",
"203.0.113.77",
"SMS code"
],
[
"2024-11-03T21:09:55Z",
"Device trusted: dv_4e8b (app); dv_2d10 removed by customer",
"app",
"dv_4e8b",
"203.0.113.77",
"SMS code"
],
[
"2025-03-02T03:18:44Z",
"Password changed",
"web",
"dv_7c22",
"203.0.113.77",
"current password"
],
[
"2026-10-01T22:58:12Z",
"Password changed (during contact-center call)",
"web",
"dv_7c22",
"203.0.113.77",
"current password"
],
[
"2026-10-01T23:02:30Z",
"Alert settings: new-device sign-in email alerts turned on (agent-assisted)",
"staff",
"",
"",
"SMS code on the call"
]
]
},
"payees": {
"columns": [
"payee",
"type",
"added",
"added_from",
"verification",
"payments_last_90_days",
"last_paid"
],
"rows": [
[
"AEP Ohio",
"bill pay",
"2022-07-05",
"web",
"none required",
3,
"2026-09-09"
],
[
"Tasha Okafor",
"Zelle",
"2021-03-14",
"app",
"SMS code",
3,
"2026-09-21"
],
[
"Dre Whitaker",
"Zelle",
"2023-07-02",
"app",
"SMS code",
0,
"2025-12-19"
]
]
},
"sign_in_history": {
"period": "2026-07-10 to 2026-10-08T14:45Z, all channels",
"columns": [
"ts",
"device_id",
"ip",
"ip_info",
"method",
"… 4 more in ambiguous.json"
],
"rows": [
[
"2026-07-12T02:42:19Z",
"dv_4e8b",
"203.0.113.77",
"Residential cable ISP, Columbus OH",
"fingerprint (app)",
"… 4 more in ambiguous.json"
],
[
"2026-07-12T11:49:55Z",
"dv_4e8b",
"192.0.2.71",
"Mobile carrier, OH",
"fingerprint (app)",
"… 4 more in ambiguous.json"
],
[
"2026-07-13T19:06:59Z",
"dv_4e8b",
"203.0.113.77",
"Residential cable ISP, Columbus OH",
"fingerprint (app)",
"… 4 more in ambiguous.json"
],
[
"2026-07-16T01:54:22Z",
"dv_4e8b",
"203.0.113.77",
"Residential cable ISP, Columbus OH",
"fingerprint (app)",
"… 4 more in ambiguous.json"
],
[
"2026-07-17T11:36:43Z",
"dv_4e8b",
"192.0.2.241",
"Mobile carrier, OH",
"fingerprint (app)",
"… 4 more in ambiguous.json"
],
"… 80 more in ambiguous.json"
]
},
"security_messages": {
"period": "2026-07-10 to 2026-10-08",
"columns": [
"ts",
"channel",
"to",
"message",
"outcome"
],
"rows": [
[
"2026-07-11T10:00:00Z",
"email",
"marcus.okafor@example.net",
"Your statement is ready",
"sent"
],
[
"2026-08-11T10:00:00Z",
"email",
"marcus.okafor@example.net",
"Your statement is ready",
"sent"
],
[
"2026-09-11T10:00:00Z",
"email",
"marcus.okafor@example.net",
"Your statement is ready",
"sent"
],
[
"2026-10-01T22:41:00Z",
"SMS",
"(614) 555-0172",
"Code to verify you with our contact center",
"entered"
],
[
"2026-10-01T22:58:32Z",
"email",
"marcus.okafor@example.net",
"Your password was changed",
"sent"
],
[
"2026-10-01T23:02:30Z",
"email",
"marcus.okafor@example.net",
"Your alert settings were changed (new-device sign-in alerts on)",
"sent"
]
]
},
"account_activity": {
"period": "posted 2026-07-10 to 2026-10-07",
"columns": [
"posted",
"account",
"type",
"description",
"amount_usd"
],
"rows": [
[
"2026-07-12",
"checking x5520",
"ACH debit",
"COLUMBIA GAS OH ONLINE PMT",
-27.16
],
[
"2026-07-12",
"checking x5520",
"debit card x3861",
"BRENMOOR HLTH CAFE COLUMBUS OH",
-11.97
],
[
"2026-07-12",
"checking x5520",
"debit card x3861",
"CHIPOTLE 1873 COLUMBUS OH",
-17.72
],
[
"2026-07-12",
"checking x5520",
"debit card x3861",
"DOORDASH*DASHPASS SAN FRANCISCO CA",
-39.03
],
[
"2026-07-14",
"checking x5520",
"ACH debit",
"WOW INTERNET AUTOPAY",
-64.99
],
"… 121 more in ambiguous.json"
]
},
"card_authorizations": {
"card": "debit x3861",
"period": "2026-09-17 to 2026-10-08, approvals and declines",
"columns": [
"ts",
"merchant",
"mcc",
"entry",
"amount_usd",
"result",
"avs",
"cvv2"
],
"rows": [
[
"2026-09-21T22:38:47Z",
"MICRO CENTER #041 COLUMBUS OH",
"5732",
"chip (05)",
59.53,
"approved (00)",
"",
""
],
[
"2026-09-22T09:30:00Z",
"PLAYSTATION NETWORK",
"5816",
"card on file (10)",
9.99,
"approved (00)",
"",
""
],
[
"2026-09-23T22:38:36Z",
"CHIPOTLE 1873 COLUMBUS OH",
"5814",
"contactless (07)",
17.25,
"approved (00)",
"",
""
],
[
"2026-09-25T16:45:00Z",
"AMAZON MKTPL*NM5TP44V2",
"5942",
"card on file (10)",
14.81,
"approved (00)",
"Y",
""
],
[
"2026-09-26T23:38:23Z",
"DOORDASH*DASHPASS SAN FRANCISCO CA",
"5812",
"card on file (10)",
50.56,
"approved (00)",
"",
""
],
"… 7 more in ambiguous.json"
]
},
"contact_center_history": {
"period": "last 12 months",
"columns": [
"ts",
"channel",
"caller",
"verification",
"reason",
"outcome"
],
"rows": [
[
"2026-04-11T19:02:00Z",
"chat (app)",
"dv_4e8b",
"signed-in app session",
"Asked to raise his Zelle limit",
"Explained limits; no change"
],
[
"2026-10-01T22:40:00Z",
"phone",
"(614) 555-0172 (on file)",
"SMS code",
"Customer said his email provider locked his email account two days earlier after a sign-in from overseas, and asked whether online banking showed anything unusual",
"Agent reviewed sign-ins: nothing unusual. Advised changing the online banking password and scanning his computer; customer changed the password on his laptop during the call and said he would run a virus scan. Agent turned on new-device sign-in alerts. Laptop left trusted (customer: 'it's my own laptop')"
]
]
},
"prior_alerts": [],
"alert": {
"alert_id": "TI-20261008-0141",
"received": "2026-10-08T14:22:00Z",
"vendor_feed": "Threat intelligence vendor: compromised credentials from infostealer logs",
"vendor_severity": "critical (log contains our bank's login and cookies)",
"where_seen": "An automated log shop on Tor ($10 per log); the shop does not show whether a log has sold",
"first_seen_by_vendor": "2026-10-04T09:30:00Z",
"newer_logs_from_same_machine": "None seen by the vendor as of the alert",
"log": {
"log_id": "5e02b9d1c4",
"malware": "Commodity infostealer sold as a service (vendor family code IS-207)",
"malware_profile": "Vendor research: builds of this family since 2026-07 add a scheduled task that re-runs the stealer every 24 hours until removed and send each new capture to the same operator; re-captures are often kept private rather than listed, so the vendor may not see them",
"captured": "2026-09-30T02:14:51Z",
"computer_name": "LAPTOP-MO4K21",
"windows_user": "marcu",
"os": "Windows 11 Home 23H2",
"browser": "Chrome 129",
"ip_at_capture": "203.0.113.77",
"timezone": "UTC-05:00 Eastern",
"screen": "1920x1200",
"antivirus": "Windows Defender",
"launched_file": "C:\\Users\\marcu\\Downloads\\VidCutPro_2026_full_setup.exe",
"sites_with_saved_passwords": 74,
"cookies": 2105,
"screenshot": "Desktop with a video-editor installer window; no account numbers or balances visible"
},
"entries_for_our_bank": {
"login_url": "https://online.ourbank.example/login",
"username": "mokafor_614",
"password": "present (compared with our stored hashes, see alert_checks)",
"cookies": [
{
"name": "tdt",
"what": "trusted-device token",
"expires": "2027-01-11"
},
{
"name": "sid",
"what": "session",
"expires": "2026-09-30T02:41:00Z"
},
{
"name": "lang",
"what": "language preference",
"expires": "2027-09-29"
}
]
},
"other_entries_of_note": [
"Password and session cookies for marcus.okafor@example.net (the email on file)",
"Login for a cryptocurrency exchange and for two gaming platforms",
"Browser autofill: full name, home address, phone number",
"No saved payment cards"
],
"vendor_match": {
"matched_on": [
"online banking username",
"email on file"
],
"vendor_confidence": "high"
}
},
"alert_checks": {
"credential_check": {
"method": "Password from the log hashed with this login's salt and algorithm and compared with the current and previous hashes; plaintext discarded, never logged",
"matches_current_password": false,
"matches_a_previous_password": true,
"which_previous_password": "The one replaced on 2026-10-01 during the contact-center call",
"current_password_set": "2026-10-01T22:58:12Z",
"current_password_set_from": "dv_7c22 (LAPTOP-MO4K21, the machine in the log) at 203.0.113.77"
},
"device_token_check": {
"token_in_log": "tdt for dv_7c22 (the laptop, trusted since 2024-01-12)",
"token_status": "active (the password change did not remove trusted devices)",
"presented_since_capture": "5 successful sign-ins, each with the password current at the time: 3 from 203.0.113.77, 1 from 198.51.100.140, 1 from 198.51.100.66; no failed attempts"
},
"log_machine_vs_our_records": "Computer name, screen size and capture IP match dv_7c22 and the customer's usual address",
"balance_check": "Not applicable: the log's screenshot shows no balances"
}
},
"questions": {
"matches_customer": {
"type": "noul",
"instructions": "Does the vendor's alert refer to this customer's own login, account or card at our bank (including a card since closed or replaced), rather than to a different person?"
},
"still_exposed": {
"type": "score",
"instructions": "How likely is it that someone other than the customer can currently use the exposed data to sign in to this customer's online banking or make payments from the customer's accounts or cards?",
"criteria": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"response": {
"type": "choice",
"instructions": "What should the bank do about this alert for this customer?",
"criteria": {
"no_action": "Log the alert and take no action: it doesn't match this customer, or nothing it exposes still works",
"reset_step_up": "Force a password 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",
"reissue_card": "Block the exposed card and issue a new card number; online banking access needs no change",
"restrict_contact": "Restrict outbound payments, new payees and contact-detail changes until the customer is reached at the phone number on file"
}
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_20d1a61207b648d0a0dd950d67440cc4",
"model": "grayson-1",
"answers": {
"matches_customer": {
"type": "noul",
"noul": 0.9948
},
"still_exposed": {
"type": "score",
"score": 2.134,
"legend": {
"0": "Very unlikely (under 10%)",
"1": "Unlikely (10-40%)",
"2": "Uncertain (40-60%)",
"3": "Likely (60-90%)",
"4": "Very likely (over 90%)"
},
"confidence": 0.1881,
"probabilities": {
"0": 0.3093,
"1": 0.1138,
"2": 0.0609,
"3": 0.1656,
"4": 0.3505
}
},
"response": {
"type": "choice",
"choice": "reset_step_up",
"confidence": 0.8298,
"probabilities": {
"no_action": 0.0298,
"reset_step_up": 0.8723,
"reissue_card": 0.0059,
"restrict_contact": 0.0919
}
}
},
"usage": {
"input_tokens": 15154,
"output_tokens": 0
}
}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_customerfilters out misattributed alerts: close alerts below a threshold automatically, and keep the probability with the alert record.still_exposedsets 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.jsonThe 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."
}| Question | Without | With your dark web response standard |
|---|---|---|
matches_customer | 95% true | 99% true |
still_exposed | 0.04 of 4, confidence 97% | 0.13 of 4, confidence 93% |
response | no_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
| Example | Input tokens | Per decision | Per 1,000 decisions | Latency |
|---|---|---|---|---|
| Obvious | 20,509 | $0.00072 | $0.72 | 283 ms |
| Legitimate | 21,373 | $0.00075 | $0.75 | 231 ms |
| Ambiguous | 15,154 | $0.00053 | $0.53 | 220 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:trueorfalsestill_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.
Related recipes
Screen card authorizations for fraud in real time
Score card authorizations for fraud and choose approve, step up or decline, next to your existing rules.
Detect insider threats in employee account access
Decide whether an employee's account access is work, snooping or insider fraud, and close, refer or suspend.
Recipes
Every use case, with its questions and cost per decision.
Account takeover
Grayson decides whether someone else is controlling an account that just changed its sign-in, contact or payout details, who owns the destination, and whether to release, step up, hold or block the money.
Insider threats
Grayson triages insider risk alerts: whether an employee opened customer accounts without a business reason, why, and whether to close, refer or suspend.