Skip to main content
Solved

YARA-L Question: Password Change Initiated from First Time Seen Country

  • July 14, 2026
  • 4 replies
  • 72 views

ar3diu
Forum|alt.badge.img+11

I am trying to write a rule for Google Workspace password resets initiated from a country that has not been seen in the last 30 days.
For some reason, the `first_seen` metric is malfunctioning (returning 0 even though the user has logged in from that country before).

Any tips?

 

$password_change.metadata.log_type = "WORKSPACE_ACTIVITY"
$password_change.metadata.product_name = "login"
$password_change.metadata.product_event_type = "password_edit"
$password_change.principal.ip_geo_artifact.location.country_or_region != ""

$user = $password_change.security_result.about.email
$country = $password_change.principal.ip_geo_artifact.location.country_or_region

match: $user, $country

outcome:
$first_seen_country = max(metrics.auth_attempts_success(
period:1d, window:30d,
metric:first_seen,
agg:max,
target.user.email_addresses:$user,
principal.ip_geo_artifact.location.country_or_region:$country))

condition:
$password_change and $first_seen_country = 0

 

Best answer by ar3diu

Thanks ​@whathehack81  for the reply. You pointed me in the right direction. Although I managed to get more accurate results by using the User ID instead of the email, and by providing the UDM field $password_change.principal.ip_geo_artifact.location.country_or_region in the first_seen metric filter instead of a placeholder variable (it does not make sense, I know, but it does seem to work).

$password_change.metadata.log_type = "WORKSPACE_ACTIVITY"
$password_change.metadata.product_event_type = "password_edit"
$password_change.principal.ip_geo_artifact.location.country_or_region != ""
$user_id = $password_change.principal.user.product_object_id
$country = $password_change.principal.ip_geo_artifact.location.country_or_region

match: 
    $user_id, $country

outcome:
    $user_email = array_distinct($password_change.security_result.about.email)
$first_seen_country = max(metrics.auth_attempts_success(
period:1d, window:30d,
metric:first_seen,
agg:max,
target.user.product_object_id:$user_id,
principal.ip_geo_artifact.location.country_or_region:$password_change.principal.ip_geo_artifact.location.country_or_region))

condition: 
    $password_change and $first_seen_country = 0

Also, your last comment seems to have been meant for another post, not this one.

4 replies

whathehack81
Forum|alt.badge.img+9

The metric is probably not malfunctioning. A return value of 0 also means that no metric series matched all supplied dimensions.

Your $user is extracted from the password-change event, but the metric filters historical authentication events using:

target.user.email_addresses: $user

principal.ip_geo_artifact.location.country_or_region: $country

Confirm that successful Workspace login events actually populate those exact two UDM fields. Depending on the parser, the authenticated identity may be under principal.user.email_addresses instead of target.user.email_addresses.

For a “not seen during the previous 30 days” check, an event count is also clearer than first_seen:

$previous_logins = sum(metrics.auth_attempts_success(

    period: 1d,

    window: 30d,

    metric: event_count_sum,

    agg: sum,

    principal.user.email_addresses: $user,

    principal.ip_geo_artifact.location.country_or_region: $country

))

Then:

condition:

    $password_change and $previous_logins = 0

Use target.user.email_addresses instead if that is where the login parser actually places the user. I would validate the historical login events in raw UDM first; otherwise 0 is indistinguishable from a genuinely new country


whathehack81
Forum|alt.badge.img+9

This will not reliably detect 30 minutes of event silence.

A YARA-L rule is evaluated when an event is processed. After the final event arrives, there is no new event at +1800 seconds to cause this condition to be evaluated:

$event and $seconds_since_last_event > 1800

It can only fire when another event later causes evaluation. For actual source-silence monitoring, use a scheduled search/health check, or a periodic heartbeat event and compare it with the last observed event for the specific source or host. Also use ingestion time rather than event time when the objective is detecting pipeline failure rather than delayed source timestamps.


ar3diu
Forum|alt.badge.img+11
  • Author
  • Silver 2
  • Answer
  • July 15, 2026

Thanks ​@whathehack81  for the reply. You pointed me in the right direction. Although I managed to get more accurate results by using the User ID instead of the email, and by providing the UDM field $password_change.principal.ip_geo_artifact.location.country_or_region in the first_seen metric filter instead of a placeholder variable (it does not make sense, I know, but it does seem to work).

$password_change.metadata.log_type = "WORKSPACE_ACTIVITY"
$password_change.metadata.product_event_type = "password_edit"
$password_change.principal.ip_geo_artifact.location.country_or_region != ""
$user_id = $password_change.principal.user.product_object_id
$country = $password_change.principal.ip_geo_artifact.location.country_or_region

match: 
    $user_id, $country

outcome:
    $user_email = array_distinct($password_change.security_result.about.email)
$first_seen_country = max(metrics.auth_attempts_success(
period:1d, window:30d,
metric:first_seen,
agg:max,
target.user.product_object_id:$user_id,
principal.ip_geo_artifact.location.country_or_region:$password_change.principal.ip_geo_artifact.location.country_or_region))

condition: 
    $password_change and $first_seen_country = 0

Also, your last comment seems to have been meant for another post, not this one.


whathehack81
Forum|alt.badge.img+9

Wow 🤣😂🤣—you’re absolutely right. I’m sorry; that last comment was meant for another post. Glad the User ID and UDM-field changes got you closer. The placeholder behavior is strange, but if it’s resolving correctly, I’d still validate the resulting metric against a few known events before relying on it in production.

RQ