Detect insider threats in employee account access

Grayson triages insider risk alerts: whether an employee opened customer accounts without a business reason, why, and whether to close, refer or suspend.

Grayson triages alerts on employee access to customer accounts: whether the employee opened or changed accounts without a business reason, how likely they are to be helping outside fraudsters, what best explains the activity, and whether to close the alert, refer it to your insider risk team or suspend the employee's access now. It reads the employee's access log for the alert window against their usual volume and their peers', the calls, chats, branch visits and tickets around each lookup, and what happened to the accounts afterward, and costs about $0.56 to $0.79 per 1,000 alerts.

  • Decides: Decide whether an employee's account access is work, snooping or insider fraud, and close, refer or suspend.
  • Call it: When access monitoring flags an employee's activity on customer accounts
  • Questions: 1 yes/no, 1 score, 2 choice
  • Cost: $0.00056 to $0.00079 per decision ($0.56 to $0.79 per 1,000) for these examples' 15,884 to 22,461 input tokens
  • Latency: 243 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 the employee's full access log for the week, eight weeks of their counts against their peers', the records around each unlinked lookup and what happened to the accounts afterward. A remote contractor changed phone numbers at night on accounts taken over the next day; a card services agent's outbound reissue calls never linked to her lookups; and a branch banker's ID-scan override let an impostor with a counterfeit license change a customer's phone number.

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.

  • access_without_business_reason: below a threshold chosen on your past alerts, close the alert and keep the answers with it; most alerts should end here.
  • enabling_fraud_likelihood: when "Likely" plus "Very likely" is high, protect the customers first by restoring changed contact details and ending the accounts' sessions.
  • explanation and action: send snooping and policy mistakes to the manager and HR, self-dealing and enabling fraud to an investigator; a person confirms every suspension.

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

Contact-center, branch and operations staff need wide access to do their jobs, so a lookup that passes an account's details to a fraud ring looks like hundreds of ordinary ones. Access rules fire mostly on legitimate work, such as outbound campaigns, transferred chats and late tickets, and can't see that the accounts a contractor opened overnight were taken over the next day.

What to send

Send the alert with the records an insider risk analyst would pull, identifying the employee by ID, role and access rather than by name:

  • The employee's job and history. Role, queue, shift, entitlements and assigned work, with their weekly counts and their peers'; an out-of-queue lookup means something only against these.
  • The full access log for the alert window, not just the flagged lookups. Reading a coworker's transactions is a different act from changing a stranger's phone number, and the ordinary work around them shows what normal looks like.
  • The contacts around each event, from every channel. Most unlinked lookups are explained by an outbound campaign call, a transferred chat, a call to the branch or a late ticket, so include the dialer, branch phone and teller records your link check doesn't read.
  • Who holds each account. Coworkers' and restricted accounts, and the high-balance or dormant ones fraud rings ask insiders to find.
  • How each change was verified, and what happened afterward. A one-time code, an ID-scan override or a ticket with no call behind it; a takeover a day after an unrequested phone number change is the strongest evidence.
  • Data leaving the workstation. Screen captures during an unlinked session suggest the information is being passed on.

Add your own policy

Each institution decides in advance where referral ends and same-day suspension begins, and many treat accounts held by employees and directors as restricted records, so put your standard in the state in your team's words. This one makes any lookup of an employee's account that the access monitor can't link to a contact a Category 1 violation with same-day suspension, whatever reason the employee gives and however briefly the record was open.

Your restricted-records rule adds this to the state of the legitimate example:

{
  "insider_risk_standard": "Insider Risk Standard IR-1, section 5 (restricted records), revised 2026-04-01. Accounts held by employees, contractors and directors are restricted records, serviced only by the Employee Banking team. Opening a restricted record is a Category 1 access violation unless the access monitor links the lookup to an inbound call, chat, in-branch interaction, ticket or case within 30 minutes, whatever reason the employee gives, however briefly the record was open and whether or not anything was changed. Outbound campaign lists are built to exclude restricted records; an agent who reaches one must skip it. For a Category 1 violation, suspend the employee's system access the same day and escalate to Insider Risk and HR; access stays suspended until the investigation closes."
}
QuestionWithoutWith your restricted-records rule
access_without_business_reason3% true5% true
enabling_fraud_likelihood0.03 of 4, confidence 98%0.05 of 4, confidence 97%
explanationlegitimate_work, confidence 96%legitimate_work, confidence 86%
actionno_action, confidence 99%suspend, confidence 88%

In the legitimate example, the mortgage processor's account on the agent's campaign list is a restricted record, and the monitor couldn't link her outbound call to it, so the action should move from closing the alert to suspending her access now, while the explanation and the fraud likelihood stay the same.

Where to call it

  • On each access-monitoring alert, before it reaches an analyst, and again when a fraud claim, takeover or DLP event hits an account they touched.
  • Before a sensitive change takes effect, such as a phone number or email change with no linked contact.
  • When the answer is uncertain, send the alert to an analyst, and don't contact the employee before you decide on their access.

Cost and latency

ExampleInput tokensPer decisionPer 1,000 decisionsLatency
Obvious20,710$0.00072$0.72243 ms
Legitimate22,461$0.00079$0.79263 ms
Ambiguous15,884$0.00056$0.56283 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/insider-threat-detection/questions.json --label access_without_business_reason=<column> --label enabling_fraud_likelihood=<column> --label explanation=<column> --label action=<column>

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

  • access_without_business_reason: true or false
  • enabling_fraud_likelihood: a level, such as "Very likely (over 90%)"
  • explanation: legitimate_work, snooping, self_dealing, enabling_fraud, policy_mistake
  • action: no_action, refer, suspend

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

Can Grayson tell snooping from an employee working with fraudsters?

It can when the evidence is in the state. Snooping usually looks like brief views of accounts the employee has a personal interest in, during their shift, with no changes and nothing exported; insiders working with fraud rings look up high-balance or dormant accounts they have no connection to, change contact details without a request, capture screens and work outside their shift, and the accounts are taken over soon after. explanation returns a probability for each, so you can see when the evidence is mixed.

Most don't, which is why most unlinked-access alerts turn out to be legitimate. Send the raw contact records near each lookup and any IT incidents that affected linking, and Grayson matches them itself, as with the outbound campaign calls, transferred chat and late ticket in the legitimate example. If you can only send the link check's result, expect more alerts to come back uncertain.

Should we include HR data or personal details about the employee?

No. Send conduct and access records, and leave out personal characteristics and circumstances such as age, nationality, health, union activity or personal finances: they say nothing about what the employee did, and using them to decide who to investigate can be discriminatory or unlawful. Identify the employee by ID and role, and keep the link to their name in your case system.

On this page