What it is
Fraud risk is a set of independent checks that run over a single application. Each check either finds something suspicious, runs cleanly, or cannot run at all because the data it needs is missing. The findings are combined into one number, that number is bucketed into a level (Low, Medium, High, Extreme), and the level is stored on the application. A job can be configured to close an application automatically once its level reaches a chosen threshold. The unit of evaluation is an application: one candidate on one job. Some checks look only at the candidate in isolation (their phone number, their resume, their address). Others look across applications, to find several candidates sharing a contact detail.In backend code an application is a
CandidateCampaignInfo row, and campaign means job. Neither
word appears in anything a customer sees.When it runs
Evaluation covers every inbound applicant on a job whose fraud risk setting is on; the setting is off until someone turns it on, in bulk withenable_fraud_risk_evaluation. Being evaluated is
separate from being shown: see Who sees it below. It runs at three points:
- A new application arrives. The checks run inline, before the application continues to resume review, so an auto-reject happens before any outreach. Sourced candidates and alternative-role additions are skipped, since neither is an inbound application.
- A candidate’s other applications are refreshed. After the inline run, the candidate’s other non-terminal applications are re-evaluated in the background so they pick up the same findings.
- A shared-contact cluster changes. When a new applicant joins a cluster (same email, phone or address as existing candidates), every other member of that cluster is queued for re-evaluation, so their scores reflect the new member. A background worker drains that queue every 30 seconds.
The signals
The catalog contains fifteen signals. The first eight look at the candidate alone; the last seven compare the candidate against other applicants. Resume history runs in the background after a new application is created and remains advisory, so it does not delay the default inline evaluation or affect the aggregate score.
Counts are of other candidates sharing the value; the applicant being scored is excluded. Internal
test emails (tenzo.ai, salv.ai) and an allowlist of test phone numbers are never fingerprinted, so
they cannot form a cluster.
Cross-org findings never name the other organization or the matching candidate. They report a count
and nothing else. Before counting, Tenzo applies the same contact-plus-name matching used when a new
candidate is deduplicated inside one organization. A matching contact record whose name similarity
is above the dedupe threshold in either comparison direction is treated as the same person and
excluded; records at or below the threshold in both directions count as different candidates. The
cross-org check does not compare resumes.
Shared IP is advisory. It is graded and shown to the reviewer, but excluded from the score, so it
can never cause an auto-reject. Kiosks, shared offices, NAT and VPNs all produce legitimately shared
IPs.
Every check ends in one of three states, and the three are distinct:
- Fail: it ran and found something.
- Pass: it ran and found nothing. This is a real result and is stored.
- Not evaluated: it could not run, because the data it needs was absent (no resume, no phone number, no claimed profile). Nothing is stored.
Scoring
Each finding contributes a score based on its level:
Those scores are summed across every finding, and the total is bucketed into the application’s
overall level:
All signals currently weigh the same. A per-signal weight table exists as the tuning surface, but it
is empty.
Signals that mostly report the same fact are grouped, and a group counts once, at its strongest
finding. The one group today is the VOIP phone check and the phone-record identity match. Most VOIP
numbers have no subscriber record, so the identity match fails on them far more often than on mobile
numbers (71% against 7% in production). Counted separately, a VOIP number alone scored 60, and one
more High finding reached Extreme. Both findings still appear to the reviewer.
A consequence of these cutoffs is that a single signal rarely escalates an application on its own.
One High finding scores 40, which buckets to Medium. One Medium scores 20, which buckets to Low.
Levels are designed to be reached by accumulation, not by any one check. This matters most for orgs
whose auto-reject threshold is High: two High findings, or one High plus two Mediums, is what it
takes.
The numbers are preliminary and expected to be tuned against live data.
What a reviewer sees
When thefraud_signals_tab flag is on, the UI offers an overall-risk badge beside the candidate’s
name and a Fraud Risk column on both a job’s Candidates table and the organization-wide
Interviews table. The server only populates those surfaces when the job setting, org default
setting and flag are all on (or for a support user in Full Access mode). Otherwise the badge is
omitted and the column shows a dash.
A detailed fraud signals panel appears in the application’s Fraud Signals tab only when the job
setting, the org default setting and the fraud_signals_tab flag are all on (support users in Full
Access mode see it for any org). The tab does not depend on ID verification: it appears for phone
screens and for video interviews that never ran an identity check, and any identity-verification
result is listed below the signals. It has three states:
- Findings. Only the signals that flagged are listed, each with its specific finding (“4 different candidates are using this same phone number”, “Name on application differs greatly from resume”).
- All checks passed. Checks ran and none flagged.
- Nothing at all. If no check was evaluated for this candidate, the section is not rendered.
- Fraud risk, on a job’s candidate list. Picks a minimum level, and defaults to High when added.
- Application Fraud Risk, on notifications. Selects specific levels, optionally including applications with no score.
What it can do automatically
- Auto-reject. A job can set a minimum level. An application reaching it moves to the
FRAUD_REJECTEDstage, which is terminal, and an explanatory note is written to the ATS. An application already in a terminal stage is left alone. - Gate ID verification. A job running ID verification on web calls can require it only for applications at or above a fraud level, rather than for everyone. An application with no stored level is skipped rather than verified. Shared links and test calls ignore the threshold, since neither has an applicant to assess.
What it does not do
- It does not gate SMS. Whether a number can receive a text is decided purely by whether the line physically supports messaging, and that decision is deliberately kept separate from fraud scoring.
- It does not block a call or an interview on its own. Only the auto-reject threshold ends an application, and only when the job configures one.
- It does not share candidate identity across organizations. Cross-org matching reports counts only.
Who sees it
Three switches must all be on before a recruiter sees a finding: the job’s fraud risk setting, the org default fraud risk setting, and thefraud_signals_tab flag. A support user in Full Access mode
sees an org’s findings whether or not that org has opted in, which is how support reads an org
exactly as that org will once the flag goes on.
Because grading and showing are separate switches, an org can be graded first and shown the results
later. Nothing is re-evaluated when the flag flips, so whatever was collected in the meantime
appears immediately and costs no further provider calls.
Where it is on today
Signal evaluation follows each job’s fraud risk setting. The flags gate what a recruiter is shown and the cross-candidate signals.
Both flags default to off, and no global default row is set, so an org without an explicit row inherits
off.
Cross-org matching is reciprocal by design: an org only matches against other orgs that have also
turned it on. Since no org has, the three cross-org signals do not fire anywhere today.
Each new application schedules a background comparison of the ten most recent unique resume
versions for supported ATSes. It does not delay application creation, does not run on generic fraud
re-evaluations, and cannot change risk or trigger auto-close. Tenzo parses the files locally and
sends the extracted resume text to the configured LLM provider. It retains structured changes and a
manifest fingerprint, not the files.
Roughly 63,000 applications across 11 orgs carry a stored level:
Because almost none of these orgs have the cross-candidate flag on, essentially every one of those
scores comes from the seven scoring candidate-scoped signals alone. Resume history is an eighth
candidate-scoped signal, but it is advisory and cannot affect those scores.
More High than Medium is not the shape the cutoffs above predict, and the High population is
currently unreliable. See Known gaps in
Fraud risk operations.
Deeper reading
The engineer-facing documentation lives with the code and goes considerably further than this page:server/fraud_risk/README.md: the scoring model, the evaluator contract, the caching mechanism, and how to add a signal.server/fraud_risk/EVALUATORS.md: one section per signal, covering every outcome it can return.server/fraud_risk/OPERATIONS.md: the full runbook.ui/src/components/transcript/FRAUD_SIGNALS.md: the reviewer panel.