Query Details

29 CSL Zscaler Category Shift Anomaly

Query

id: c329d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e
name: "Zscaler ZIA - Sudden Category Shift - User Accessing New High-Risk URL Categories"
version: 1.0.0
kind: Scheduled
description: |
  Detects users accessing URL categories they have never accessed in the previous 7 days, where those categories represent high-risk or policy-violating content: gambling, adult/pornography, proxy avoidance, personal VPN, dating, extremism, tasteless, or illegal content. A sudden category shift may indicate compromised credentials being used by an attacker browsing freely, a policy bypass attempt, or an insider threat. MITRE ATT&CK: T1078 (Valid Accounts), T1090 (Proxy), T1048.
severity: Medium
requiredDataConnectors:
  - connectorId: CommonSecurityEvents
    dataTypes:
      - CommonSecurityLog
queryFrequency: PT1H
queryPeriod: P7D
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
  - CommandAndControl
relevantTechniques:
  - T1078
  - T1090
query: |
    let HighRiskCategories = dynamic([
        "GAMBLING", "ADULT_CONTENT", "NUDITY", "DATING",
        "PROXY_AVOIDANCE_ANONYMIZERS", "PERSONAL_VPN", "ANONYMIZING_UTILITIES",
        "EXTREMISM_ADVOCACY", "TASTELESS", "ILLEGAL_OR_QUESTIONABLE"]);
    let recentWindow    = 1h;
    let baselineWindow  = 7d;
    let baseline = CommonSecurityLog
        | where TimeGenerated between (ago(baselineWindow) .. ago(recentWindow))
        | where DeviceVendor == "Zscaler" and isnotempty(SourceUserName)
        | summarize BaselineCategories = make_set(DeviceCustomString2)
            by SourceUserName;
    let recent = CommonSecurityLog
        | where TimeGenerated > ago(recentWindow)
        | where DeviceVendor == "Zscaler" and isnotempty(SourceUserName)
        | where DeviceCustomString2 in (HighRiskCategories)
        | summarize
            RecentCategories = make_set(DeviceCustomString2),
            RequestCount     = count(),
            Domains          = make_set(DestinationHostName, 10)
            by SourceUserName;
    recent
    | join kind=leftouter baseline on SourceUserName
    | extend BaselineCategories = coalesce(BaselineCategories, dynamic([]))
    | extend NewCategories = set_difference(RecentCategories, BaselineCategories)
    | where array_length(NewCategories) > 0
    | project SourceUserName, NewCategories, RequestCount, Domains, RecentCategories
    | order by RequestCount desc
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: SourceUserName
customDetails:
  RequestCount: RequestCount
  NewCategories: NewCategories
alertDetailsOverride:
  alertDisplayNameFormat: "Zscaler Category Shift - {{SourceUserName}} accessing new risk categories"
  alertDescriptionFormat: "User {{SourceUserName}} accessed {{RequestCount}} requests in new high-risk categories not seen in past 7 days: {{NewCategories}}."
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT6H
    matchingMethod: Selected
    groupByEntities:
      - Account
    groupByAlertDetails: []
    groupByCustomDetails: []

Explanation

This query is designed to detect unusual behavior by monitoring users who suddenly start accessing high-risk URL categories that they haven't accessed in the past week. The high-risk categories include gambling, adult content, proxy avoidance, personal VPNs, dating, extremism, tasteless, or illegal content. Such behavior could indicate compromised credentials, policy bypass attempts, or insider threats.

Here's a simplified breakdown of the query:

  1. High-Risk Categories: A list of URL categories considered high-risk is defined.

  2. Time Windows:

    • Recent Window: The last hour.
    • Baseline Window: The past seven days, excluding the last hour.
  3. Baseline Data: Collects data on which URL categories each user accessed during the baseline window.

  4. Recent Data: Collects data on which high-risk URL categories each user accessed during the recent window.

  5. Comparison:

    • The query compares the recent data against the baseline data for each user.
    • It identifies new high-risk categories accessed by users that were not accessed in the baseline period.
  6. Output:

    • Lists users who accessed new high-risk categories, the number of requests made, and the domains visited.
    • Results are ordered by the number of requests.
  7. Alerting:

    • If any new high-risk categories are detected, an alert is generated.
    • The alert includes details such as the username, the number of requests, and the new categories accessed.
  8. Incident Management:

    • Incidents are created for detected alerts, with options for grouping by user account.

This query helps in identifying potential security threats by flagging unusual access patterns to high-risk content.

Details

David Alonso profile picture

David Alonso

Released: March 2, 2026

Tables

CommonSecurityLog

Keywords

ZscalerUserURLCategoriesGamblingAdultContentNudityDatingProxyAvoidanceAnonymizersPersonalVPNAnonymizingUtilitiesExtremismAdvocacyTastelessIllegalOrQuestionableCommonSecurityLogSourceUserNameDeviceVendorDeviceCustomStringDestinationHostNameAccountFullName

Operators

letdynamicbetweenagoisnotemptysummarizemake_setincountjoinkindextendcoalesceset_differencearray_lengthwhereprojectorder by

Actions