NetScaler CVE-2026-88779 SAML Denial-of-Service Zero-Day Hunt

Threat Overview

Citrix disclosed CVE-2026-88779, a memory-overflow vulnerability in customer-managed NetScaler ADC and NetScaler Gateway that can produce denial of service when the appliance is configured as a SAML service provider or SAML identity provider in conjunction with Gateway or AAA functionality. Citrix rates the issue CVSS 8.7 and confirms targeted attacks against unmitigated deployments. Repeated triggering can keep the service unavailable; Citrix states that its analysis identified an availability impact and no impact to customer-data integrity.

CISA added the vulnerability to the Known Exploited Vulnerabilities catalog with an October 7, 2026 federal remediation deadline. This is distinct from CVE-2026-88771 and CVE-2026-88772 disclosed earlier: appliances patched for those flaws still require the newer CVE-2026-88779 build. Citrix has not published an exploit payload, attacker IP set, or appliance-compromise indicator for this availability attack. Hunting must therefore combine confirmed configuration exposure, SAML/AAA request concentration, Global Deny List statistics, appliance crash/restart telemetry, and external availability signals.

References

Impacted Systems

  • Vendor/product: Customer-managed NetScaler ADC and NetScaler Gateway.
  • Affected versions: 14.1 before 14.1-73.41; 13.1 before 13.1-64.28; NetScaler ADC 14.1-FIPS before 14.1-73.41 FIPS; NetScaler ADC 13.1-FIPS and 13.1-NDcPP before 13.1-37.282.
  • Fixed versions: 14.1-73.41, 13.1-64.28, 14.1-73.41 FIPS, and 13.1-37.282 FIPS/NDcPP, or later supported releases on the applicable line.
  • Deployment: Customer-managed physical, virtual, or cloud-hosted appliances. Citrix-managed Gateway Service and Citrix-managed Adaptive Authentication were updated by Citrix.
  • Role/configuration prerequisite: Gateway or AAA virtual server with SAML configured as an SP (add authentication samlAction) or IdP (add authentication samlIdPProfile).
  • Exposure: Network reachability to the affected Gateway/AAA SAML flow, commonly Internet-facing for remote access.
  • Temporary mitigation: Citrix Global Deny List signature version 24 or later on supported interim ranges with virtual patching enabled; this is not a substitute for upgrading.

Why this matters

NetScaler Gateways are identity and remote-access choke points. A targeted attacker who repeatedly triggers this issue can sustain authentication-service unavailability without compromising data. The flaw is actively exploited, narrowly configuration-dependent, and requires an additional upgrade even on appliances remediated for the late-September NetScaler vulnerabilities.

Exploitation Status

Targeted exploitation is vendor-confirmed, and CISA KEV-listed. Citrix says unmitigated appliances have been attacked and repeated triggering may maintain service unavailability. Public sources do not identify the affected organizations, exploitation volume, payload structure, or durable IOCs. Citrix has not identified customer-data integrity impact from this CVE.

What this hunt looks for

SAML configuration exposure, concentrated SAML or AAA requests, Global Deny List hits, SAML-processing errors, appliance crashes or restart loops, HA failover, connection resets, rare request sources, and availability loss correlated with request bursts.

Required logs

NetScaler ns.log through Syslog; NetScaler, AppFlow, reverse-proxy, WAF, or firewall request telemetry in CommonSecurityLog or AzureDiagnostics; authoritative appliance version and SAML configuration inventory; and health or availability telemetry.

Hunt 1 — First-pass NetScaler SAML exposure and mitigation evidence

let lookback = 14d;
Syslog
| where TimeGenerated >= ago(lookback)
| where SyslogMessage has_any ("add authentication samlAction", "add authentication samlIdPProfile", "stat denylist global AAA_REQUEST", "Encrypted Version", "Default Signatures")
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Evidence=make_set(SyslogMessage, 20) by Computer
| order by LastSeen desc

Hunt 2 — Concentrated SAML or AAA requests from one source

let lookback = 14d;
union isfuzzy=true CommonSecurityLog, AzureDiagnostics
| where TimeGenerated >= ago(lookback)
| extend Raw=tostring(pack_all()), Src=coalesce(column_ifexists("SourceIP", ""), column_ifexists("clientIp_s", ""), column_ifexists("CallerIPAddress", "")), Dst=coalesce(column_ifexists("DestinationIP", ""), column_ifexists("host_s", ""))
| where Raw has_any ("saml", "SAMLRequest", "SAMLResponse", "/nf/auth/", "AAA_REQUEST")
| summarize Requests=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Samples=make_set(substring(Raw, 0, 400), 3) by Src, Dst, bin(TimeGenerated, 5m)
| where Requests >= 25
| order by Requests desc

Hunt 3 — Global Deny List or App Firewall actions involving AAA/SAML

let lookback = 14d;
Syslog
| where TimeGenerated >= ago(lookback)
| where ProcessName has_any ("nslog", "nsconf", "nsaaad") or SyslogMessage has_any ("denylist", "APPFW", "AAA_REQUEST", "SAML")
| where SyslogMessage has_any ("DENY", "BLOCK", "DROP", "HIT", "VIOLATION", "AAA_REQUEST")
| summarize Events=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Messages=make_set(SyslogMessage, 10) by Computer, ProcessName, bin(TimeGenerated, 5m)
| order by Events desc

Hunt 4 — SAML processing errors followed by appliance crash or restart signals

let lookback = 14d;
let SamlErrors = Syslog
| where TimeGenerated >= ago(lookback)
| where ProcessName has_any ("nsaaad", "nslog") or SyslogMessage has_any ("SAML", "saml")
| where SyslogMessage has_any ("error", "failed", "invalid", "overflow", "abort")
| project Computer, ErrorTime=TimeGenerated, SamlMessage=SyslogMessage;
Syslog
| where TimeGenerated >= ago(lookback)
| where SyslogMessage has_any ("segmentation fault", "core dump", "crash", "restarted", "reboot", "failover", "secondary", "not responding")
| join kind=inner SamlErrors on Computer
| where TimeGenerated between (ErrorTime .. ErrorTime + 15m)
| project TimeGenerated, Computer, ErrorTime, SamlMessage, ProcessName, CrashMessage=SyslogMessage
| order by TimeGenerated desc

Hunt 5 — Repeated NetScaler crash, restart, or HA failover sequences

let lookback = 14d;
Syslog
| where TimeGenerated >= ago(lookback)
| where SyslogMessage has_any ("segmentation fault", "core dump", "crash", "restarted", "reboot", "HA failover", "primary", "secondary", "node state")
| summarize Events=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Processes=make_set(ProcessName, 10), Messages=make_set(SyslogMessage, 10) by Computer, bin(TimeGenerated, 30m)
| where Events >= 2
| order by Events desc

Hunt 6 — Connection reset or denied-session surge to a NetScaler target

let lookback = 14d;
CommonSecurityLog
| where TimeGenerated >= ago(lookback)
| where DeviceVendor has_any ("Citrix", "NetScaler") or DeviceProduct has_any ("NetScaler", "ADC", "Gateway")
| where DeviceAction has_any ("reset", "deny", "drop", "failed") or Message has_any ("reset", "timeout", "unavailable")
| summarize Events=count(), Sources=dcount(SourceIP), SourceSample=make_set(SourceIP, 20), Actions=make_set(DeviceAction, 10) by DestinationIP, DestinationPort, bin(TimeGenerated, 5m)
| where Events >= 20
| order by Events desc

Hunt 7 — Rare sources generating SAML traffic to NetScaler

let baseline = 30d;
let recent = 2d;
let Base = CommonSecurityLog
| where TimeGenerated between (ago(baseline) .. ago(recent))
| where DeviceVendor has_any ("Citrix", "NetScaler") or RequestURL has_any ("saml", "/nf/auth/")
| summarize by SourceIP, DestinationIP;
CommonSecurityLog
| where TimeGenerated >= ago(recent)
| where DeviceVendor has_any ("Citrix", "NetScaler") or RequestURL has_any ("saml", "/nf/auth/")
| join kind=leftanti Base on SourceIP, DestinationIP
| summarize Requests=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), URLs=make_set(RequestURL, 20), Actions=make_set(DeviceAction, 10) by SourceIP, DestinationIP
| order by Requests desc

Hunt 8 — Availability-loss correlation around SAML request bursts

let lookback = 14d;
let Bursts = CommonSecurityLog
| where TimeGenerated >= ago(lookback)
| where RequestURL has_any ("saml", "/nf/auth/") or Message has_any ("SAMLRequest", "AAA_REQUEST")
| summarize Requests=count(), Sources=dcount(SourceIP) by DestinationIP, Window=bin(TimeGenerated, 5m)
| where Requests >= 25;
Syslog
| where TimeGenerated >= ago(lookback)
| where SyslogMessage has_any ("not responding", "unavailable", "failover", "restarted", "crash", "core dump")
| extend Window=bin(TimeGenerated, 5m)
| join kind=inner Bursts on Window
| project TimeGenerated, Computer, DestinationIP, Requests, Sources, ProcessName, SyslogMessage
| order by TimeGenerated desc

Detection Notes

  • Hunt 1 is an exposure check, not proof of vulnerability. Configuration commands may not be forwarded to Syslog; validate directly on each appliance. Confirm both the build and the SAML/Gateway/AAA precondition.
  • Legitimate identity-provider retries, user surges, and misconfiguration can create SAML bursts. Highest-signal results correlate a concentrated source or request sequence with nsaaad errors, a process crash, appliance restart, HA transition, or service outage.
  • Crash and restart message text varies by NetScaler build and Syslog configuration. Tune the terms to local ns.log samples; generic “primary” and “secondary” text can be noisy.
  • Citrix has not published an exploit request pattern or attacker IOC set. These queries detect conditions and effects consistent with exploitation, not a definitive CVE signature.
  • The Global Deny List counter can show blocked AAA requests, but a hit does not prove CVE-2026-88779 exploitation. Signature version 24 and virtual patching status should be validated operationally.
  • Missing NetScaler-native Syslog, HTTP/WAF request logs, configuration inventory, or health/availability telemetry prevents meaningful confirmation in Sentinel.