In October 2023, Citrix disclosed CVE-2023-4966 in NetScaler ADC and NetScaler Gateway. Nicknamed Citrix Bleed, it let an unauthenticated attacker read memory contents out of the appliance — and what that memory contained was valid session tokens for people who were legitimately logged in.
With a stolen token, an attacker does not log in. They resume. There is no password to guess and no multi-factor prompt to defeat, because the session they are joining already satisfied both. Ransomware operators used it heavily, and it went into CISA's Known Exploited Vulnerabilities catalogue.
Then came the part worth the whole post. Citrix's advisory told customers that upgrading was not sufficient on its own: because tokens stolen before the upgrade stayed valid afterwards, administrators also had to terminate existing sessions. Organisations that patched and closed the ticket were still compromised days later, by credentials they had already handed over and never revoked.
- CVE
- CVE-2023-4966, commonly called Citrix Bleed
- Product
- NetScaler ADC and NetScaler Gateway, when configured as a gateway or AAA virtual server
- Class
- Sensitive information disclosure — an out-of-bounds read leaking session material
- Severity
- Critical — CVSS 9.4 per Citrix's advisory
- Disclosed
- 10 October 2023, with exploitation observed beforehand; added to CISA's Known Exploited Vulnerabilities catalogue
- Impact
- Theft of valid session tokens, session hijack without credentials, and multi-factor authentication bypassed entirely — because MFA had already been satisfied when the session was created
- The sting
- Patching did not invalidate tokens already stolen. Active sessions had to be terminated as a separate step.
The root cause, in one sentence
A session token was treated as proof of identity, while nothing in the system could withdraw that proof once it escaped.
The memory-disclosure bug is the uninteresting half; that one is Citrix's to fix and they fixed it. The half that belongs to everyone building applications is the design underneath: a bearer token is a password that your application issued, that your users cannot see, cannot rotate and cannot report as stolen. Every assumption you make about how hard it is to obtain one is an assumption, and your revocation story is what remains when the assumption fails.
No exploitation detail here either. If you run NetScaler, the action is to verify your build against Citrix's advisory and — the step people skipped — terminate existing sessions after upgrading. The same logic applies to any token-leak bug in any product: the patch stops new theft, it does not retract what was already taken.
The five session failures we find in applications
You are unlikely to ship a memory-disclosure bug. You are very likely to ship one of these.
1. Tokens that outlive the event that should kill them
The user logs out, changes their password, has their role reduced, or is deprovisioned entirely by HR — and a token issued before that moment keeps working. We test this directly, and it fails more often than any other item on our list. The logout button frequently clears the client's cookie while the server retains no record that the session should be refused, which means it only logs out users who were not attacking you.
2. MFA that is satisfied once and never revisited
This is the Citrix Bleed lesson exactly. MFA is treated as a gate at the door rather than a property of the session, so anyone who obtains a post-authentication token inherits an MFA-satisfied identity. Sensitive operations — changing payment details, adding an administrator, exporting the customer database — should require reauthentication at the moment they happen, not a factor that was presented at breakfast.
3. Stateless tokens with no way back
A signed JWT that the server validates by signature alone cannot be revoked; it is valid until it expires, by design. Teams choose this for scalability and then discover there is no answer to "revoke this user's access now". It is a workable design with short lifetimes, refresh tokens and a denylist for emergencies — and a dangerous one with a twenty-four-hour expiry and nothing else, which is what we usually find.
4. Tokens that leak through ordinary channels
Session identifiers in URLs end up in server logs, browser history, Referer headers sent to third parties, analytics pipelines and support screenshots. Tokens in localStorage are readable by any cross-site scripting flaw, whereas an HttpOnly cookie is not. No exotic vulnerability is needed to steal a token that the application is already writing somewhere it should not be.
5. Sessions that never rotate
If the identifier a visitor holds before logging in is the same one they hold afterwards, anyone who can set that value in advance owns the resulting authenticated session. The same applies to privilege transitions — elevating to administrator should mint a new session, not upgrade the existing one in place.
"We have MFA" is the most common reason a team gives for not worrying about session handling, and Citrix Bleed is the counter-example in its purest form: not one authentication factor was defeated, because the attacker never authenticated. Where MFA sits in the session lifecycle matters more than whether you have it.
How we test for it
- Replay after logout. Capture an authenticated session, log out through the application, then reuse the captured token. It must fail. This single test has a remarkable hit rate.
- Replay after a password change, from a different browser. Changing a password is what a user does when they believe they have been compromised; if it does not terminate other sessions, it has not helped them at all.
- Replay after a permission change. Demote an administrator to a standard user while their session is live, then retry an administrative action with the old token. Authorisation is frequently resolved once, at login, and cached for the life of the session.
- Inspect what the token actually is. Random server-side identifier or self-contained JWT? If it is a JWT, is the signature verified, is the algorithm pinned, and is anything inside it trusted that the client could change? What is the expiry, and is there any revocation path at all?
- Follow the token everywhere it goes. URLs, logs,
Refererheaders, third-party scripts, browser storage, cached responses, error pages. Then check the cookie flags —HttpOnly,Secure, and aSameSitevalue that actually suits the application. - Test the lifecycle end to end. Idle timeout, absolute timeout, session fixation at login, rotation on privilege change, concurrent sessions, and whether "sign out everywhere" does what it claims.
- Check reauthentication on the operations that matter — payment details, email address changes, administrator creation, bulk export. A hijacked session should still hit a wall at the genuinely dangerous actions.
Each result is written up with the captured request, the point in the lifecycle it was replayed at, and the response proving it was accepted — reproducible by your team without us in the room.
Six things to check in your own application this week
- Log in, log out, replay the old token. If it works, you have a finding and it took ninety seconds to find.
- Make a password reset terminate every other session for that user, and say so in the confirmation message, so the action means what the user thinks it means.
- Give yourself a revocation path that works under pressure — a server-side session store, or short-lived tokens plus refresh tokens plus a denylist. Test it by actually revoking someone, not by reading the code.
- Set an absolute session lifetime, not only an idle timeout. An idle timeout alone means a session kept warm by a background tab lives forever.
- Require reauthentication for changing payment details, changing the account email, creating administrators and exporting data in bulk.
- Get tokens out of URLs, keep them in
HttpOnlycookies rather thanlocalStoragewhere your architecture allows, and confirm they are not being written to your logs — that last one is usually a one-line grep of yesterday's access log.
Sessions, access control and business logic are where the serious findings live, and they are the three things automated tooling is worst at. That is the gap our testing is built around.