Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-8452-check — Behavioral patch-state detector for Citrix NetScaler CVE-2026-8452. Sends crafted SAML requests to determine whether the PrefixList size check is present, without exploiting or corrupting memory. | Kitploit
Tools/GitHubGitHub/bishopfox/cve-2026-8452-check
Vulnerability ScannersVulnerability AnalysisWeb SecurityNetwork Security
GitHubbishopfox/cve-2026-8452-check

CVE-2026-8452-check

Behavioral patch-state detector for Citrix NetScaler CVE-2026-8452. Sends crafted SAML requests to determine whether the PrefixList size check is present, without exploiting or corrupting memory.

View Repository
1131 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Citrix NetScaler SAML PrefixList Heap Overflow — Patch-State Detection Script

A safe, non-destructive patch-state check for CVE-2026-8452, the pre-authentication heap overflow in the Citrix NetScaler ADC / NetScaler Gateway SAML signature canonicalizer (CTX696604, CVSS 8.8). An oversized exclusive-canonicalization PrefixList overflows a fixed-size buffer during canonicalization, which NetScaler performs before validating the signature that carries it — so the whole path is reachable with no credentials, no session, and no valid signature. Reported by Michael Tucker of the JPMorgan Chase XOR team; root-cause and exploitation analysis credit to watchTowr Labs.

This script does not exploit the bug and does not corrupt memory. It answers one question per target: is the fix present on this appliance? — determined behaviourally, by observing the patch rather than guessing the build.

Is it Safe to Run?

Yes. It is designed for production and assessment use:

  • The probe stays below the corruption threshold. 575 bytes is long enough that patched and unpatched builds answer differently, and well below the length at which an unpatched appliance's memory corruption begins. Validated by measurement on appliances spanning both supported branches and both patch states, including both fix builds.
  • The threshold it clears is a fixed code constant, not a property of one deployment. Fixed builds accept a PrefixList of 512 bytes and reject 513 or more. That limit was located to the byte, is identical on both supported branches, and does not move with the appliance's configuration or with the shape of the surrounding SAML message — confirmed by probing both routes, which wrap the value in substantially different amounts of XML, and finding they change behaviour at the same byte. 575 clears the limit by 63 bytes, so the verdict does not depend on how a target happens to be set up.
  • Patching does not make appliances reject long SAML values generally. The limit applies to the PrefixList attribute specifically. Inflating other fields past it — assertion consumer service URLs, issuer names, algorithm identifiers, digest and signature values — changes nothing on a fixed build, so applying the fix should not cause a working SAML configuration to start failing.
  • No memory is corrupted and no process is restarted. On a patched build the probe is rejected at the size check; on an unpatched build it fails benignly inside the parser. Neither reaches the overflow.
  • Nothing sensitive enters scan output. The probe carries only synthetic namespace-prefix tokens, and the tool reports a verdict, not response bodies.
  • Two fixed lengths, never a sweep. The 575-byte probe, plus a 35-byte control on the route that answers. The tool never sweeps a range of lengths and never sends any other length.

If you modify the probe, do not change PROBE_PREFIXES and do not sweep lengths. 575 bytes is load-bearing. Other PrefixList lengths can destabilize an appliance, in at least one case on a build that carries this fix, so a length sweep is not a safe way to explore this bug and shorter is not safer.

How it Works

Patched builds reject an oversized PrefixList cleanly, with a distinctive message. Unpatched builds fall through the parser and return a generic internal error. One identical request, two different answers:

575-byte PrefixListResponse
Unpatched500 Internal Server Error 43549
Patched200 Malformed Assertion sent to Netscaler

Two routes are tried, IdP first, stopping as soon as one gives an answer. Either is sufficient alone, and together they cover both SAML roles:

RouteRequestRequires
1 (first)POST /saml/login — signed AuthnRequest, PrefixList in ds:SignedInfoa SAML IdP policy bound to the targeted vserver
2 (fallback)POST /cgi/samlauth — SAMLResponse, PrefixList in the assertion signaturea SAML SP assertion consumer service on the targeted vserver

The IdP route goes first because it is the more robust of the two. It is insensitive to the Issuer value, to the AssertionConsumerServiceURL, and to clock skew — an IssueInstant well outside the appliance's skew tolerance still discriminates correctly, because canonicalization precedes the time check as well as the signature check.

The route-1 AuthnRequest must be signed. An unsigned one returns 200 Malformed Assertion sent to Netscaler on patched and unpatched builds, which is byte-identical to the patched signal, so a probe that omits the signature block reports every appliance as patched. The signature does not need to be valid, and this tool's is not; it only has to be present, because its SignedInfo is what carries the PrefixList into the canonicalizer.

Behaviour at the fix boundary

Both supported branches change behaviour exactly at their fix build, on both routes:

BuildVerdict
13.1-63.16last vulnerable 13.1VULNERABLE
13.1-63.18first fixed 13.1PATCHED
14.1-66.59vulnerable 14.1VULNERABLE
14.1-72.61first fixed 14.1PATCHED

13.1-63.16 and 63.18 are consecutive releases, so the change is attributable to the patch itself rather than to drift across intervening builds.

Those are the builds where this fix first appeared, and the probe detects exactly that transition. They are no longer the builds to upgrade to: later bulletins have superseded them, so 13.1-63.18 and 14.1-72.61 both answer PATCHED here while remaining exposed to newer issues. See Remediation for the current fixed builds.

Why not fingerprint the build?

Because it cannot work on this bug, even in principle. 13.1-63.16 and 13.1-63.18, the builds immediately either side of the fix, serve byte-identical tmindex.html, base.css and resources.js — the fix touches no web asset. Static asset hashes also collide across branches, so a hash-based approach can resolve a vulnerable appliance to a patched build and report it as clean, which is the worst failure mode a detection tool has. Build fingerprinting is therefore deliberately not implemented. Patch state comes from the probe, or from show ns version where you have credentials.

Requirements

  • Python 3.8+, standard library only — no third-party packages.

Usage

# single target
./cve_2026_8452_check.py https://gateway.example.com

# a specific AAA / Gateway virtual server
./cve_2026_8452_check.py https://gateway.example.com:9443

# scan a list, one target per line ('#' comments allowed), compact output
./cve_2026_8452_check.py -f targets.txt --brief

# machine-readable output for pipelines
./cve_2026_8452_check.py -f targets.txt --json > results.json

Point the tool at the Gateway or AAA virtual server, not the management interface. The precondition is per virtual server, so an appliance with several VIPs needs each one tested.

Options

FlagDescription
URLOne or more https://HOST[:PORT] targets
-f, --targets-file FILERead targets from a file (one per line; # comments)
-b, --briefSingle aligned line per target — verdict, target, reason tag — for scanning many hosts
--jsonEmit structured JSON results
--no-colorDisable coloured output (also honours NO_COLOR and non-TTY)
--timeout SECSPer-request timeout (default: 15)

Examples

An unpatched appliance, answered on the IdP route and confirmed against the control:

Download Tool