Detection rules › Panther

OpenAI Credential Stuffing

Severity
medium
Group by
actor.session.user.email
Log types
OpenAI.Audit
Tags
OpenAI, Credential Access
Reference
https://platform.openai.com/docs/api-reference/audit-logs
Source
github.com/panther-labs/panther-analysis

Detects credential stuffing attacks against OpenAI accounts by tracking the number of distinct source IP addresses submitting failed login attempts against the same email address within a short timeframe. Unlike brute force from a single IP, credential stuffing distributes attempts across many IPs to evade rate limiting. This rule complements OpenAI.BruteForce.Login.Success, which confirms account compromise once a successful login follows the failures.

MITRE ATT&CK coverage

TacticTechniques
Credential AccessT1110.004 Brute Force: Credential Stuffing

Rule body yaml

AnalysisType: rule
RuleID: "OpenAI.CredentialStuffing"
DisplayName: "OpenAI Credential Stuffing"
Filename: openai_credential_stuffing.py
Enabled: true
LogTypes:
  - OpenAI.Audit
Severity: Medium
Threshold: 5
DedupPeriodMinutes: 30
Description: >
  Detects credential stuffing attacks against OpenAI accounts by tracking the number of
  distinct source IP addresses submitting failed login attempts against the same email
  address within a short timeframe. Unlike brute force from a single IP, credential
  stuffing distributes attempts across many IPs to evade rate limiting. This rule
  complements OpenAI.BruteForce.Login.Success, which confirms account compromise
  once a successful login follows the failures.
Runbook: |
  1. Review the distinct source IPs from the failed login attempts and check if they belong to known anonymization infrastructure (VPNs, Tor exit nodes, residential proxies) using threat intelligence
  2. Query OpenAI audit logs for all login.succeeded and login.failed events against the targeted email address within the past 30 minutes to identify all contributing source IPs and determine if any attempt succeeded — the alert context shows only the IP of the final triggering event, not all contributing IPs
  3. Check for other alerts involving the targeted email address in the past 7 days and look for login.succeeded events from unfamiliar locations or devices to assess whether account compromise has already occurred
Reference: https://platform.openai.com/docs/api-reference/audit-logs
Tags:
  - OpenAI
  - Credential Access
Reports:
  MITRE ATT&CK:
    - TA0006:T1110.004 # Credential Access: Credential Stuffing
Tests:
  - Name: Match - Failed Login
    ExpectedResult: true
    Log:
      id: "audit_log-failed001"
      type: "login.failed"
      effective_at: 1702857600
      object: "organization.audit_log"
      actor:
        type: "session"
        session:
          user:
            id: "user-123"
            email: "user@company.com"
          ip_address: "203.0.113.100"
          user_agent: "Mozilla/5.0"
      login_failed:
        error_code: "invalid_credentials"
        error_message: "Invalid username or password"
  - Name: Match - Failed Login Different IP
    ExpectedResult: true
    Log:
      id: "audit_log-failed002"
      type: "login.failed"
      effective_at: 1702857610
      object: "organization.audit_log"
      actor:
        type: "session"
        session:
          user:
            id: "user-123"
            email: "user@company.com"
          ip_address: "198.51.100.25"
          user_agent: "python-requests/2.28.0"
      login_failed:
        error_code: "invalid_credentials"
        error_message: "Invalid username or password"
  - Name: No Match - Successful Login
    ExpectedResult: false
    Log:
      id: "audit_log-success001"
      type: "login.succeeded"
      effective_at: 1702857620
      object: "organization.audit_log"
      actor:
        type: "session"
        session:
          user:
            id: "user-123"
            email: "user@company.com"
          ip_address: "203.0.113.100"
          user_agent: "Mozilla/5.0"
  - Name: No Match - Non-Login Event
    ExpectedResult: false
    Log:
      id: "audit_log-api001"
      type: "api_key.created"
      effective_at: 1702857700
      object: "organization.audit_log"
      actor:
        type: "session"
        session:
          user:
            id: "user-123"
            email: "user@company.com"
          ip_address: "203.0.113.100"
          user_agent: "Mozilla/5.0"

Detection logic

Condition

type eq "login.failed"

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
typeeq
  • login.failed

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
emailactor.session.user.email
ip_addressactor.session.ip_address
error_codelogin_failed.error_code