Query Details

Zscaler ZPA - First-Time Access to Internal Application - Possible Lateral Movement

33 CSL ZPA First Time App Access

Query

let recentWindow   = 1h;
let baselineWindow = 14d;
let baseline = CommonSecurityLog
    | where TimeGenerated between (ago(baselineWindow) .. ago(recentWindow))
    | where DeviceVendor == "Zscaler" and DeviceProduct has "ZPA"
    | where DeviceAction !in ("block", "BLOCK", "Blocked", "Failed", "Error")
    | where isnotempty(SourceUserName) and isnotempty(DestinationHostName)
    | summarize HistoricApps = make_set(DestinationHostName)
        by SourceUserName;
let recent = CommonSecurityLog
    | where TimeGenerated > ago(recentWindow)
    | where DeviceVendor == "Zscaler" and DeviceProduct has "ZPA"
    | where DeviceAction !in ("block", "BLOCK", "Blocked", "Failed", "Error")
    | where isnotempty(SourceUserName) and isnotempty(DestinationHostName)
    | summarize
        RecentApps      = make_set(DestinationHostName),
        ConnectionCount = count(),
        SourceIPs       = make_set(SourceIP, 5)
        by SourceUserName;
recent
| join kind=leftouter baseline on SourceUserName
| extend HistoricApps = coalesce(HistoricApps, dynamic([]))
| extend FirstTimeApps = set_difference(RecentApps, HistoricApps)
| where array_length(FirstTimeApps) > 0
| project SourceUserName, FirstTimeApps, ConnectionCount, SourceIPs, RecentApps
| order by ConnectionCount desc

Explanation

This query is designed to detect unusual access patterns in a Zscaler Private Access (ZPA) environment, which could indicate potential security threats such as lateral movement by an attacker. Here's a simple breakdown of what the query does:

  1. Purpose: It identifies users who have accessed internal applications for the first time within the last hour, where they haven't accessed these applications in the previous 14 days. This could suggest unauthorized exploration of internal resources.

  2. Data Source: The query uses data from the CommonSecurityLog, specifically looking at logs from Zscaler ZPA.

  3. Time Frames:

    • Recent Window: The last hour (1h).
    • Baseline Window: The previous 14 days (14d).
  4. Process:

    • Baseline Data: It collects a list of applications each user has accessed in the past 14 days.
    • Recent Data: It gathers data on applications accessed by users in the last hour.
    • Comparison: It compares the two datasets to find applications that users have accessed for the first time in the recent window.
  5. Output: The query produces a list of users who have accessed new applications, along with details such as the number of connections made, the new applications accessed, and the source IPs used.

  6. Alerting: If any first-time access is detected, an alert is generated with details about the user and the new applications accessed. The alert is categorized under tactics like Lateral Movement and Initial Access, referencing MITRE ATT&CK techniques T1078 (Valid Accounts) and T1021 (Remote Services).

  7. Incident Management: The system is set up to create incidents for these alerts, with configurations for grouping related alerts by user account.

In summary, this query helps security teams monitor for potential unauthorized access or lateral movement within their network by identifying users accessing new internal applications, which could indicate a security breach or policy testing.

Details

David Alonso profile picture

David Alonso

Released: March 2, 2026

Tables

CommonSecurityLog

Keywords

ZscalerZPAUsersInternalApplicationsDeviceVendorDeviceProductDeviceActionSourceUserNameDestinationHostNameSourceIP

Operators

letbetweenagohas!inisnotemptysummarizemake_setby>joinkind=leftouteronextendcoalescedynamicset_differencewherearray_lengthprojectorder bydesc

Severity

Medium

Tactics

LateralMovementInitialAccess

MITRE Techniques

Frequency: PT1H

Period: P14D

Actions

GitHub