Fraud Event Sequence Data Model

This document presents a simplified, event-oriented extension of the standard Transaction & Account Data Model. The model introduces specific event nodes to represent various types of operations.
LLM Version of Data Model:
1. Business Scenario
This example illustrates a typical fraud scenario that can be detected by analyzing a chronological sequence of events:
-
A malicious actor steals the customer’s login details and gains access to their account. This event is represented by the
Authentication
node. -
The attacker changes key account information to take control:
-
Changes the phone number (
ChangePhone
node) -
Changes the email address (
ChangeEmail
node) -
Changes the physical address (
ChangeAddress
node)
-
-
The attacker adds an external account (
AddExternalAccount
node) to facilitate transferring the victim’s funds. -
Finally, the attacker transfers money to the external account (
Transfer
node).
Each event node can be linked to other nodes that provide context or details. For example, during a ChangePhone
event, both the previous and new phone numbers are recorded.
2. Evolutions
This data model is intentionally simple, but it can be extended to include additional event types or greater complexity to better reflect real-world scenarios:
-
ChangeDrivingLicence
-
ChangePassport
-
ContactSupport
-
etc.
3. Objectives
The objectives of this data model are to:
-
Accelerate investigations for fraud officers
-
Simplify the identification of new fraud patterns
-
Detect weak signals or rapid sequences of suspicious events
-
Facilitate the writing of Cypher queries for pattern detection
4. Node Labels and Properties
Newly Added Nodes |
Authentication
Properties:
-
method
(String): Authentication method used (eg: "email", "phone_number") -
status
(String): Status of the authentication attempt (eg: "success", "failed") -
createdAt
(DateTime): Date and time when the authentication was established
AddExternalAccount
Properties:
-
createdAt
(DateTime): Date and time when the external account was added
5. Relationship Types and Properties
6. Customer enhancements
Velocity Tracking Enhancement:
A significant improvement opportunity exists in tracking the speed of account changes, which is a critical fraud indicator. Rapid successive changes often signal automated attacks or coordinated fraud attempts.
Proposed Enhancement:
-
Add temporal properties to
:NEXT
relationships between consecutive events -
Include
timeDelta
(duration between events) -
Track cumulative change velocity over rolling time windows
Benefits:
-
Detect automated attack patterns through abnormally fast event sequences
-
Identify human vs. bot behavior based on realistic timing patterns
-
Enable real-time velocity-based fraud scoring and blocking
Failed Attempts Tracking Enhancement:
The current model focuses on successful events but should capture failed attempts, which are often stronger fraud indicators than successful ones.
Proposed Enhancement:
-
Create dedicated nodes for failed authentication attempts before successful login
-
Track rejected change requests and their failure reasons
-
Maintain audit trails of all attempt types, not just successful ones
Benefits:
-
Failed login attempts followed by successful access often indicate credential stuffing
-
Multiple rejected change requests may signal social engineering attempts
-
Pattern analysis of failed attempts can reveal attack methodologies
7. Minimal Demo Code
The following Cypher code extends the standard Transaction & Account Data Model with event-based fraud detection capabilities. This code demonstrates how a typical account takeover fraud unfolds through a chronological sequence of events.
Prerequisites: Run the Transaction & Account Data Model demo code first to create the base customer, accounts, and session data.
//--------------------
// Match existing base model entities (created by Transaction & Account Data Model demo)
//--------------------
MATCH (c:Customer {customerId: "CUS001"})
MATCH (s:Session {sessionId: "SESS001"})
MATCH (a:Account:Internal {accountNumber: "ACC001"})
MATCH (originalPhone:Phone {number: "447971020304"})
MATCH (originalEmail:Email {address: "john@example.com"})
MATCH (originalAddr:Address {addressLine1: "123 High Street"})
MATCH (uk:Country {code: "GB"})
MATCH (us:Country {code: "US"})
//--------------------
// Create event-based extensions: Fraud Event Sequence
//--------------------
// Event 1: Fraudulent Authentication (attacker gains access to customer account)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us
CREATE (e1:Authentication {
method: "email",
status: "success",
createdAt: datetime("2024-03-01T14:30:00")
})
// Event 2: Change phone number (5 minutes later)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1
CREATE (e2:ChangePhone {
createdAt: datetime("2024-03-01T14:35:00")
})
CREATE (newPhone:Phone {
number: "447800123456",
countryCode: "+44",
createdAt: datetime("2024-03-01T14:35:00")
})
// Replace customer's phone relationship (simulate successful account takeover)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, newPhone
MATCH (c)-[r:HAS_PHONE]->(originalPhone) DELETE r
CREATE (c)-[:HAS_PHONE {since: datetime("2024-03-01T14:35:00")}]->(newPhone)
// Event 3: Change email address (2 minutes later)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, newPhone
CREATE (e3:ChangeEmail {
createdAt: datetime("2024-03-01T14:37:00")
})
CREATE (newEmail:Email {
address: "attacker.new@protonmail.com",
domain: "protonmail.com",
createdAt: datetime("2024-03-01T14:37:00")
})
// Replace customer's email relationship (simulate successful account takeover)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, e3, newPhone, newEmail
MATCH (c)-[r:HAS_EMAIL]->(originalEmail) DELETE r
CREATE (c)-[:HAS_EMAIL {since: datetime("2024-03-01T14:37:00")}]->(newEmail)
// Event 4: Change address (3 minutes later)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, e3, newPhone, newEmail
CREATE (e4:ChangeAddress {
createdAt: datetime("2024-03-01T14:40:00")
})
CREATE (newAddr:Address {
addressLine1: "999 Fraud Street",
addressLine2: "Unit 13",
postTown: "London",
postCode: "E1 6XX",
region: "Greater London",
latitude: 51.5171,
longitude: -0.0574,
createdAt: datetime("2024-03-01T14:40:00")
})
// Update customer's address relationships (simulate successful account takeover)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, e3, e4, newPhone, newEmail, newAddr
MATCH (c)-[r:HAS_ADDRESS]->(originalAddr) SET r.isCurrent = false, r.lastChangedAt = datetime("2024-03-01T14:40:00") DELETE r
CREATE (c)-[:HAS_ADDRESS {
addedAt: datetime("2024-03-01T14:40:00"),
lastChangedAt: datetime("2024-03-01T14:40:00"),
isCurrent: true
}]->(newAddr)
CREATE (newAddr)-[:LOCATED_IN]->(uk)
// Event 5: Add external account (10 minutes later)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, e3, e4, newPhone, newEmail, newAddr
CREATE (e5:AddExternalAccount {
createdAt: datetime("2024-03-01T14:50:00")
})
CREATE (fraudAccount:Account:External:HighRiskJurisdiction {
accountNumber: "FRAUD123456789",
accountType: null,
openDate: null,
closedDate: null,
suspendedDate: null
})
// Event 6: Transfer money to external account (5 minutes later)
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, e3, e4, e5, newPhone, newEmail, newAddr, fraudAccount
CREATE (e6:Transfer {
createdAt: datetime("2024-03-01T14:55:00")
})
CREATE (fraudTransaction:Transaction {
transactionId: "TXN_FRAUD_001",
amount: 15000.00,
currency: "GBP",
date: datetime("2024-03-01T14:55:00"),
message: "Emergency transfer",
type: "SWIFT"
})
//--------------------
// Create event-based relationships
//--------------------
// Chain events chronologically and create all remaining relationships
WITH c, s, a, originalPhone, originalEmail, originalAddr, uk, us, e1, e2, e3, e4, e5, e6, newPhone, newEmail, newAddr, fraudAccount, fraudTransaction
CREATE (e1)-[:NEXT]->(e2)-[:NEXT]->(e3)-[:NEXT]->(e4)-[:NEXT]->(e5)-[:NEXT]->(e6)
CREATE (s)-[:HAS_AUTHENTICATION]->(e1)
CREATE (s)-[:HAS_CHANGE_PHONE]->(e2)
CREATE (s)-[:HAS_CHANGE_EMAIL]->(e3)
CREATE (s)-[:HAS_CHANGE_ADDRESS]->(e4)
CREATE (s)-[:HAS_ADD_EXTERNAL_ACCOUNT]->(e5)
CREATE (s)-[:HAS_TRANSFER]->(e6)
CREATE (e2)-[:OLD_PHONE]->(originalPhone)
CREATE (e2)-[:NEW_PHONE]->(newPhone)
CREATE (e3)-[:OLD_EMAIL]->(originalEmail)
CREATE (e3)-[:NEW_EMAIL]->(newEmail)
CREATE (e4)-[:OLD_ADDRESS]->(originalAddr)
CREATE (e4)-[:NEW_ADDRESS]->(newAddr)
CREATE (fraudAccount)-[:IS_HOSTED]->(us)
CREATE (e5)-[:ADD_ACCOUNT]->(fraudAccount)
CREATE (e6)-[:HAS_TRANSACTION]->(fraudTransaction)
CREATE (a)-[:PERFORMS]->(fraudTransaction)-[:BENEFITS_TO]->(fraudAccount)
CREATE (c)-[:CONNECTS]->(e1)