Detection rules › Panther

Google Workspace OAuth Token Requests from New IP

Severity
medium
Tags
GSuite, Initial Access, Valid Accounts, GAIA, Credential Theft, OAuth
Reference
https://businessinsights.bitdefender.com/the-chain-reaction-new-methods-for-extending-local-breaches-in-google-workspace
Source
github.com/panther-labs/panther-analysis

Alerts when users request OAuth tokens from IP addresses they haven't used in the past 30 days, with 3+ requests indicating active usage. This may indicate GAIA credential theft where attackers use stolen refresh tokens to request access tokens from their infrastructure.

MITRE ATT&CK coverage

Rule body yaml

AnalysisType: scheduled_rule
DisplayName: "Google Workspace OAuth Token Requests from New IP"
DedupPeriodMinutes: 1440
RuleID: "Google.Workspace.OAuth.Token.New.IP"
Description: |
  Alerts when users request OAuth tokens from IP addresses they haven't used in the past 30 days,
  with 3+ requests indicating active usage. This may indicate GAIA credential theft where attackers
  use stolen refresh tokens to request access tokens from their infrastructure.
ScheduledQueries:
  - Google Workspace OAuth Token Requests from New IPs
Enabled: false
Filename: gsuite_oauth_token_new_ip_rule.py
Reference: https://businessinsights.bitdefender.com/the-chain-reaction-new-methods-for-extending-local-breaches-in-google-workspace
Runbook: |
  1. Query GSuite.ActivityEvent for all OAuth token requests (applicationName: "token") by the user in the 24 hours before and after the alert to identify the full scope of token activity from the new IP address
  2. Check if the new IP address is associated with cloud providers, VPN services, proxy networks, or residential ISPs, and compare its geographic location to the user's typical login locations in the past 30 days
  3. Search for other authentication anomalies for this user in the past 7 days, including login type changes, rapid multi-IP authentication, password changes, or device compromise warnings
Severity: Medium
Tags:
  - GSuite
  - Initial Access
  - Valid Accounts
  - GAIA
  - Credential Theft
  - OAuth
Reports:
  MITRE ATT&CK:
    - TA0001:T1078.004
    - TA0006:T1550
SummaryAttributes:
  - user
  - new_ip
  - app_names
Tests:
  - Name: Google Chrome from new IP
    ExpectedResult: true
    Log:
      user: user@example.com
      new_ip: 1.2.3.4
      request_count: 5
      app_names: ["Google Chrome"]
      client_ids: ["12345.apps.googleusercontent.com"]
      first_seen: "2024-01-15 10:00:00.000"
      last_seen: "2024-01-15 10:05:00.000"

Detection logic

Filter

import re
def normalize_username(email):
    if not email:
        return None
    username = email.split("@")[0] if "@" in email else email
    return re.sub(r"[^a-z0-9]", "", username.lower())
def rule(_):
    return True
def title(event):
    user = event.get("user", "<UNKNOWN_USER>")
    new_ip = event.get("new_ip", "<UNKNOWN_IP>")
    request_count = event.get("request_count", 0)
    return (
        f"Google Workspace: User [{user}] made {request_count} OAuth token requests "
        f"from new IP [{new_ip}]"
    )
def alert_context(event):
    user = event.get("user")
    return {
        "user": user,
        "username_normalized": normalize_username(user),
        "new_ip": event.get("new_ip"),
        "request_count": event.get("request_count"),
        "app_names": event.get("app_names"),
        "client_ids": event.get("client_ids"),
        "first_seen": event.get("first_seen"),
        "last_seen": event.get("last_seen"),
        "description": (
            "User requested OAuth tokens from an IP address not seen in the past 30 days, "
            "with multiple requests indicating active usage"
        ),
    }

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.

Field
user
new_ip
request_count
app_names
client_ids
first_seen
last_seen