CVE-2023-30861 Overview
Flask is a lightweight WSGI web application framework widely used for building Python web applications. A session cookie caching vulnerability exists in Flask that can cause responses containing data intended for one client to be cached and subsequently sent by a proxy to other clients. If the proxy also caches Set-Cookie headers, it may send one client's session cookie to other clients, leading to potential session hijacking and unauthorized access.
Critical Impact
Under specific conditions, session cookies can be leaked to unauthorized clients through caching proxies, potentially allowing attackers to impersonate other users and access sensitive data.
Affected Products
- Palletsprojects Flask versions prior to 2.2.5
- Palletsprojects Flask versions 2.3.x prior to 2.3.2
- Applications hosted behind caching proxies that do not strip cookies
Discovery Timeline
- 2023-05-02 - CVE CVE-2023-30861 published to NVD
- 2024-11-21 - Last updated in NVD database
Technical Details for CVE-2023-30861
Vulnerability Analysis
This vulnerability occurs when a Flask application is deployed behind a caching proxy and specific session configurations are enabled. The issue stems from Flask's handling of the Vary: Cookie HTTP header, which is critical for instructing caching proxies to store separate cached copies of responses for different cookie values.
Vulnerable versions of Flask only set the Vary: Cookie header when the session is explicitly accessed or modified during a request. However, when SESSION_REFRESH_EACH_REQUEST is enabled (which is the default setting), Flask will refresh the session cookie to update its expiration time even if the application code never accesses or modifies the session. In this refresh scenario, the Vary: Cookie header is not set, causing caching proxies to potentially serve the same cached response (including the refreshed session cookie) to multiple different clients.
The vulnerability requires all of the following conditions to be met:
- The application must be hosted behind a caching proxy that does not strip cookies or ignore responses with cookies
- The application sets session.permanent = True
- The application does not access or modify the session at any point during a request
- SESSION_REFRESH_EACH_REQUEST is enabled (the default)
- The application does not set a Cache-Control header to indicate that a page is private or should not be cached
Root Cause
The root cause is a missing Vary: Cookie header in HTTP responses when Flask refreshes the session cookie without the session being explicitly accessed or modified. This omission causes caching proxies to incorrectly cache responses with session cookies and serve them to other clients.
Attack Vector
The attack is network-based and requires no authentication or user interaction. An attacker can exploit this vulnerability by waiting for a victim to make a request through a vulnerable caching proxy. When the victim's response (containing their session cookie) is cached without the proper Vary: Cookie header, subsequent requests from the attacker may receive the cached response with the victim's session cookie.
The fix adds the Vary: Cookie header whenever the session is accessed, ensuring caching proxies properly differentiate cached responses based on cookies:
samesite = self.get_cookie_samesite(app)
httponly = self.get_cookie_httponly(app)
+ # Add a "Vary: Cookie" header if the session was accessed at all.
+ if session.accessed:
+ response.vary.add("Cookie")
+
# If the session is modified to be empty, remove the cookie.
# If the session is empty, return without setting the cookie.
if not session:
Source: GitHub Flask Commit
Detection Methods for CVE-2023-30861
Indicators of Compromise
- HTTP responses from Flask applications missing the Vary: Cookie header when session cookies are present
- Multiple users receiving identical session cookies in cached responses
- Anomalous session activity showing users accessing accounts they do not own
- Caching proxy logs showing responses with Set-Cookie headers being served to multiple distinct clients
Detection Strategies
- Monitor HTTP response headers for Flask applications to verify Vary: Cookie is present when session cookies are set
- Implement logging at the proxy layer to detect when responses containing Set-Cookie headers are being cached and served to multiple clients
- Review application code for patterns where session.permanent = True is set but the session is not accessed during request processing
- Audit Flask version deployed across your infrastructure to identify vulnerable instances
Monitoring Recommendations
- Set up alerts for authentication anomalies where users appear to be logged in as other users
- Monitor proxy cache hit rates for pages that should be user-specific
- Implement session validation checks that verify session cookies match the expected client IP or user agent
- Review access logs for patterns indicating session cookie reuse across different IP addresses
How to Mitigate CVE-2023-30861
Immediate Actions Required
- Upgrade Flask to version 2.3.2 or 2.2.5 or later immediately
- Configure your caching proxy to not cache responses containing Set-Cookie headers
- Add explicit Cache-Control: private or Cache-Control: no-store headers to responses that involve session handling
- If upgrading is not immediately possible, set SESSION_REFRESH_EACH_REQUEST = False in your Flask configuration
Patch Information
Palletsprojects has released security patches addressing this vulnerability. The fix ensures that the Vary: Cookie header is set whenever the session is accessed, modified, or refreshed. Upgrade to one of the following versions:
- Flask 2.3.2 - for applications on the 2.3.x branch
- Flask 2.2.5 - for applications on the 2.2.x branch
Additional security advisories have been issued by Debian and NetApp. For detailed information, see the GitHub Security Advisory.
Workarounds
- Set SESSION_REFRESH_EACH_REQUEST = False in Flask configuration to prevent automatic session refresh without access
- Configure your reverse proxy or CDN to never cache responses containing Set-Cookie headers
- Add Cache-Control: private header to all responses that may involve session handling
- Implement application-level caching controls that explicitly set proper cache headers for all routes
# Flask configuration workaround (app.py)
# Add to your Flask app configuration to disable automatic session refresh:
# app.config['SESSION_REFRESH_EACH_REQUEST'] = False
# Nginx proxy configuration to avoid caching responses with Set-Cookie:
# proxy_no_cache $http_set_cookie;
# proxy_cache_bypass $http_set_cookie;
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


