Skip to main content

Tuesday's Tip of the Week: Vetting Compromised Service Accounts via UDM

  • July 21, 2026
  • 3 replies
  • 49 views

dnehoda
Staff
Forum|alt.badge.img+18

July 21, 2026

 

Why Service Accounts Are High-Value Targets

 

Service accounts are the keys to your cloud kingdom. Unlike human accounts, they rarely have MFA, they often hold broad permissions, and their activity is easy to overlook because "that is just automation." Attackers know this. A compromised service account gives persistent, privileged access without triggering the usual user-behavior alerts.

 

Using UDM Search, we can hunt for the telltale signs.

 

Query 1: Service Account Logins from Unexpected IPs

 

Service accounts typically authenticate from a small set of known compute resources. Logins from outside that range deserve investigation.

 

The query is formatted below:

 

metadata.event_type = "USER_LOGIN" AND metadata.log_type = "GCP_CLOUDAUDIT" AND principal.user.email_addresses = /gserviceaccount\.com/ AND NOT net.ip_in_range_cidr(principal.ip, "10.0.0.0/8")

 

This query finds any GCP service account authenticating from an IP outside your internal `10.0.0.0/8` range. Replace the CIDR with your actual compute subnets.

 

Query 2: Service Account API Calls Outside Business Hours

 

Legitimate automation often runs on schedules. API calls at 3:00 AM on a Sunday from a service account that only runs during business hours are suspicious.

 

The query is formatted below:

 

metadata.log_type = "GCP_CLOUDAUDIT" AND principal.user.email_addresses = /gserviceaccount\.com/ AND metadata.event_type = "USER_RESOURCE_ACCESS"

 

Run this query with the time picker set to weekends or late-night hours. Review which service accounts appear and what methods they called via the `metadata.product_event_type` field in the results.

 

Query 3: Service Accounts Accessing Unusual Resources

 

A service account that normally reads from Cloud Storage suddenly calling Secret Manager or IAM Admin APIs is a red flag.

 

The query is formatted below:

 

metadata.log_type = "GCP_CLOUDAUDIT" AND principal.user.email_addresses = /gserviceaccount\.com/ AND metadata.product_event_type = /SecretManager/ AND metadata.event_type = "USER_RESOURCE_ACCESS"

 

Swap `SecretManager` for other sensitive services: `SetIamPolicy`, `CreateServiceAccountKey`, `instances.setMetadata`. Each of these represents a lateral movement or persistence technique.

 

The "Authenticate Then Recon" Pattern

 

Compromised service accounts follow a predictable sequence. First, the attacker authenticates using stolen credentials. Then, they enumerate what the account can access, calling multiple distinct API methods in rapid succession. Finally, they act on their objectives, whether that is exfiltrating data, creating backdoor credentials, or pivoting to other accounts.

 

When you spot a service account making an unusual volume of distinct API calls in a short window, especially discovery-oriented calls like `list`, `get`, or `describe` methods, treat it as a potential compromise.

 

These hunt queries are valuable for one-time investigations. To run them continuously, turn these hunt patterns into persistent YARA-L detection rules that fire automatically when the conditions are met.

 

 

 

3 replies

whathehack81
Forum|alt.badge.img+6

Nice hunting workflow. One addition I would make is treating USER_LOGIN as supporting evidence rather than a required first stage.

## A service account operating with credentials that are already valid may be visible primarily through its API activity. Requiring a preceding USER_LOGIN event could therefore miss the API-only portion of the sequence.

## The method-diversity portion can be operationalized directly in UDM Search:

metadata.log_type = "GCP_CLOUDAUDIT"

principal.user.email_addresses = /gserviceaccount\.com/

metadata.event_type = "USER_RESOURCE_ACCESS"

metadata.product_event_type != ""

 

match:

  principal.user.email_addresses

 

outcome:

  $event_count = count_distinct(metadata.id)

  $distinct_methods = count_distinct(metadata.product_event_type)

  $methods = array_distinct(metadata.product_event_type)

  $source_ips = array_distinct(principal.ip)

 

order:

  $distinct_methods desc

 

limit:

  50

Run this over a short time window and investigate service accounts with unusually high method diversity or methods outside their established role.

I would use count_distinct(metadata.id) rather than count(metadata.id) because repeated UDM fields can expand into multiple evaluation rows and inflate the apparent event volume.

Before converting it into a persistent rule, verify which fields are actually populated for the relevant Cloud Audit events in Event Viewer, particularly principal.ip and metadata.product_event_type.


dnehoda
Staff
Forum|alt.badge.img+18
  • Author
  • Staff
  • July 21, 2026

thats a statistical search rather than a basic UDM search which is fine but we’re not there yet in our weekly tips.  


whathehack81
Forum|alt.badge.img+6

Understood — thanks for clarifying. I jumped ahead into statistical search rather than staying within the basic UDM Search scope of this week’s tip. The aggregation approach may be useful later in the series when you cover statistical searches.