In August 2025, Workday disclosed that attackers had tricked employees into handing over credentials and then logged into a third-party CRM platform. Reports strongly suggest Salesforce was the system abused.

The breach wasn’t caused by weak passwords or a missing patch. The attackers had valid credentials, and Salesforce trusted them blindly. The result: sensitive data was exposed.

The lesson is clear: credentials prove who you are, but not whether the login makes sense.

FraudGuard’s User History APIs, paired with Salesforce Login Flows, give enterprises the missing context. They make every login a decision point: not just is the password correct? But does this login fit the user’s historical pattern, IP reputation, and device profile?


The Problem: Salesforce Trusted the Password Alone

When a user logs into Salesforce today:

  • The username + password are verified
  • MFA may or may not be triggered
  • If credentials are correct, Salesforce grants access

That’s where trust stops. There’s no check against:

  • Prior login history (locations, devices, IPs)
  • Whether the IP is flagged as a VPN, TOR, open public proxy, common malicious user
  • ASN, ISP, or geolocation anomalies - its unlikely the user logs in from Japan on Tuesday and Ireland on Wednesday

This blind spot is exactly what the Workday attackers exploited.


The Solution: FraudGuard’s User History APIs

FraudGuard offers three APIs that extend Salesforce authentication with contextual intelligence:

  • POST /api/v1/user-history/check
    • Logs a new login attempt (user, IP, user agent)
    • Sets the stage for real-time evaluation
  • GET /api/v1/user-history/
    • Retrieves the latest login event
    • Returns a recommendation object (Allow, Challenge, or Block) with reasons
  • GET /api/v1/user-history/list/
    • Returns up to 100 prior login events for a user
    • Helps analysts and security teams detect long-term anomalies

Real-Time Prevention Example

Step 1: Record the Login Attempt

POST https://api.fraudguard.io/api/v1/user-history/check
Authorization: Basic <base64 username:password>
Content-Type: application/json

{
  "user_id": "LZsuJGwxV5y7sTF5yFvvFA1LRuH1gVvM",
  "ip": "125.12.194.229",
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4280.85 Safari/537.36"
}

Response

{
  "user_id": "LZsuJGwxV5y7sTF5yFvvFA1LRuH1gVvM",
  "ip": "125.12.194.229",
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4280.85 Safari/537.36"
}

Step 2: Evaluate the Attempt in Real-Time

GET https://api.fraudguard.io/api/v1/user-history/LZsuJGwxV5y7sTF5yFvvFA1LRuH1gVvM
Authorization: Basic <base64 username:password>

Response

{
  "user_id": "LZsuJGwxV5y7sTF5yFvvFA1LRuH1gVvM",
  "ip": "125.12.194.229",
  "city": "Tokyo",
  "country": "Japan",
  "timestamp": "2024-11-14 03:53:25",
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4280.85 Safari/537.36",
  "recommendation": {
    "action": "Challenge",
    "reason": "New Device"
  }
}

Even though the password was valid, FraudGuard recommends Challenge because this login came from a new device in an unexpected location.


Step 3: Enforcement in Salesforce Login Flow

Salesforce Login Flows run immediately after authentication but before full access is granted. They’re the perfect enforcement point.

Flow outline:

  • HTTP Callout → send login details to FraudGuard (POST /check)
  • Decision Node → call GET /user-history/ to retrieve recommendation
  • If Allow → grant access
  • If Challenge → force step-up MFA, email verification, etc
  • If Block → deny login and alert SecOps

This turns every Salesforce login into a context-aware decision backed by FraudGuard intelligence.

Forensics & Analyst Drill-Down

When an anomalous login is flagged, analysts can pull the user’s history for deeper investigation:

GET https://api.fraudguard.io/api/v1/user-history/list/LZsuJGwxV5y7sTF5yFvvFA1LRuH1gVvM
Authorization: Basic <base64 username:password>

Response

{
  "user_id": "LZsuJGwxV5y7sTF5yFvvFA1LRuH1gVvM",
  "user_history": [
    {
      "ip": "125.12.194.229",
      "city": "Tokyo",
      "country": "Japan",
      "timestamp": "2024-11-14 03:53:25",
      "user_agent": "Mozilla/5.0 ... Chrome/84.0.4280.85 Safari/537.36",
      "recommendation": {
        "action": "Challenge",
        "reason": "New Device"
      }
    },
    {
      "ip": "1.162.194.229",
      "city": "New Taipei",
      "country": "Taiwan",
      "timestamp": "2024-11-14 03:49:59",
      "user_agent": "Mozilla/5.0 ... Chrome/87.0.4280.85 Safari/537.36",
      "recommendation": {
        "action": "Block",
        "reason": "Bad IP Reputation"
      }
    }
  ]
}

From this view, it’s obvious the user’s typical Comcast logins have been replaced by high-risk IPs in Asia. Security teams can now correlate these attempts across multiple accounts.


Why This Would Have Prevented the Workday Breach

The Workday attackers succeeded because Salesforce asked: “Is the password correct?”

With FraudGuard, Salesforce would also ask: “Does this login make sense for this user?”

  • Credentials valid → ✅
  • IP consistent with history → ❌
  • Device/location new → ❌
  • FraudGuard recommendation → Challenge or Block

That single check would have broken the attack chain.


The Workday incident proves that passwords are no longer enough. Attackers exploit trust gaps in CRMs, and enterprises pay the price.

By embedding FraudGuard’s User History APIs into Salesforce Login Flows, customers can turn every login into a context-aware decision point. The result? Fewer breaches and safer customer data.

🔒 Passwords prove identity. FraudGuard provides the context.

Want more info? Check out our blog post covering User History APIs in more technical depth.

Ready to get started Sign up for a free 14 day trial now at FraudGuard.io or email us at hello@fraudguard.io to learn more.