CVE-2025-47278
NoneCVSS
—
EPSS
0.2%
Published
May 13, 2025
CISA due date
—
Cloudanix analysis
Some Flask applications may keep using an older session secret after a planned rotation, which can prolong risk if that old secret was ever exposed.
- Exploitation
- Local Privilege
- Attacker needs
- High Privilege
- Complexity
- Moderate
- Impact
- Denial Of Service
- Component
- Web Framework
- Class
- Cryptographic Weakness
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
Flask 3.1.0 incorrectly orders the key list passed to itsdangerous when SECRET_KEY_FALLBACKS is configured for session signing key rotation. Instead of using the newest/current SECRET_KEY for newly signed session cookies, Flask may sign new sessions with the last fallback key, which is intended to be an older key used only for verification during rotation. Existing and new sessions remain cryptographically signed, so this is not a direct unsigned-cookie or arbitrary tampering vulnerability; the main technical impact is failed or delayed key rotation and continued dependence on a stale signing key. Risk is meaningful primarily for applications that enabled SECRET_KEY_FALLBACKS, especially if an older key was exposed or was intended to be retired.
Why it matters to the business
Affected applications may believe they have rotated session-signing secrets when they are actually continuing to use an older key, extending the operational risk window if that older key is weak, mishandled, or previously exposed. This can undermine incident response plans, delay safe retirement of compromised secrets, and cause avoidable session management disruption during key-rotation projects. The issue is not in CISA KEV, is not known to be used in ransomware campaigns, has very low EPSS likelihood, and has no known public exploit maturity, so it should generally be prioritized as a hygiene and cryptographic correctness fix rather than an emergency internet-wide exploitation event.
How an attack unfolds
An attacker cannot typically exploit this flaw remotely by sending a crafted request alone. The vulnerable condition exists when a Flask 3.1.0 application has opted into session key rotation using SECRET_KEY_FALLBACKS. In that state, Flask signs newly issued session cookies with a stale fallback key instead of the intended current key. If an attacker already has privileged local access, access to application configuration, or prior knowledge of an old session-signing key, the bug may extend the usefulness of that old key because the application continues to rely on it for newly signed sessions. Without prior compromise or access to signing secrets, the flaw does not provide a practical path to forge sessions or bypass authentication.
How to fix it
Upgrade Flask from 3.1.0 to Flask 3.1.1 or later. For source-based deployments, ensure the fix corresponding to pallets/flask commit 7fff56f5172c48b6f3aedf17ee14ef5c2533dfd1 is included. Review applications that define SECRET_KEY_FALLBACKS and confirm the newest/current key is set as SECRET_KEY and older keys are present only for temporary verification during rotation. After upgrading, complete the intended key rotation by removing stale fallback keys once the session transition window has passed. If any old signing key may have been exposed, force session invalidation, rotate SECRET_KEY again, and minimize or remove fallback acceptance where operationally possible.
How to confirm the fix worked
Confirm package inventory shows Flask 3.1.1 or later and not Flask 3.1.0. For Python environments, validate with commands such as python -m flask --version, python -c "import flask; print(flask.__version__)" where supported, pip show Flask, pip freeze, poetry show flask, or the organization’s software composition analysis tooling. Review configuration for SECRET_KEY_FALLBACKS; applications not using this setting are not affected by the key-ordering behavior. In a controlled non-production test, configure a current key and fallback key, issue a new session after upgrade, and verify that the cookie validates with the current key and not only with the stale fallback key. Also confirm stale fallback keys are removed after the approved rotation period.
Typical attack path
- Identify or gain access to a Flask 3.1.0 application that uses client-side signed sessions and has SECRET_KEY_FALLBACKS configured.
- Obtain knowledge of an older fallback signing key through a separate compromise, configuration leak, source exposure, backup exposure, or privileged local access.
- Take advantage of the application continuing to sign new session cookies with the stale fallback key rather than the intended current key.
- Use the stale key to analyze or potentially craft signed session data only if the application stores security-relevant state in the client-side session and the attacker has sufficient knowledge of the signing format and application behavior.
- Maintain access until the application is upgraded and the old fallback key is removed or invalidated.
How to detect it
There are no widely reported exploitation campaigns or distinctive network indicators for this issue, and exploitation would generally depend on prior access to old signing keys rather than a recognizable request pattern. To assess whether the issue may have contributed to an incident, review application dependency inventories for Flask 3.1.0 and configuration repositories or runtime configuration for SECRET_KEY_FALLBACKS. Examine secret-management audit logs for reads, exports, or changes involving Flask SECRET_KEY values and fallback keys. Review source-control history, CI/CD logs, container images, deployment artifacts, backups, and crash/debug output for accidental exposure of SECRET_KEY or SECRET_KEY_FALLBACKS values. In application logs, investigate unusual session continuity after a key rotation, unexpected successful authentication using sessions that should have been invalidated, abnormal admin activity after secret rotation, or large numbers of session-cookie validation failures during rotation windows. Because Flask signed session cookies are normally client-side and validation failures may not be logged by default, additional application instrumentation may be required to distinguish cookies signed with old versus current keys.
What your security team should do
- Inventory Flask applications and prioritize those running Flask 3.1.0 with SECRET_KEY_FALLBACKS configured.
- Upgrade affected deployments to Flask 3.1.1 or later, or apply the upstream fix commit 7fff56f5172c48b6f3aedf17ee14ef5c2533dfd1 for source-pinned builds.
- Review secret-management records and incident history to determine whether any fallback session-signing key was previously exposed or should be considered untrusted.
- If an old key may be compromised, rotate SECRET_KEY after patching and invalidate active sessions rather than relying on fallback acceptance.
- Add dependency checks that flag Flask 3.1.0 and configuration checks that identify SECRET_KEY_FALLBACKS usage during application security reviews.
- Treat this as low exploitation urgency but important cryptographic hygiene, especially for applications with privileged admin sessions or sensitive account state stored in Flask sessions.
The record
Flask is a web server gateway interface (WSGI) web application framework. In Flask 3.1.0, the way fallback key configuration was handled resulted in the last fallback key being used for signing, rather than the current signing key. Signing is provided by the `itsdangerous` library. A list of keys can be passed, and it expects the last (top) key in the list to be the most recent key, and uses that for signing. Flask was incorrectly constructing that list in reverse, passing the signing key first. Sites that have opted-in to use key rotation by setting `SECRET_KEY_FALLBACKS` care likely to unexpectedly be signing their sessions with stale keys, and their transition to fresher keys will be impeded. Sessions are still signed, so this would not cause any sort of data integrity loss. Version 3.1.1 contains a patch for the issue.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| PyPI | flask | 3.1.0 | 3.1.1 |
| Chainguard | airflow-3 | 0 | 3.0.1-r1 |
| Chainguard | airflow-3-bitnami-compat | 0 | 3.0.1-r1 |
| Chainguard | airflow-3-compat | 0 | 3.0.1-r1 |
| Chainguard | airflow-3-iamguarded-compat | 0 | 3.0.1-r1 |
| Chainguard | airflow-core-3 | 0 | 3.0.1-r1 |
| Chainguard | airflow-core-3-compat | 0 | 3.0.1-r1 |
| Chainguard | airflow-core-3-oci-entrypoint | 0 | 3.0.1-r1 |
| Chainguard | emissary | 0 | 3.10.0-r3 |
| Chainguard | emissary-apiext | 0 | 3.10.0-r3 |
| Chainguard | emissary-oci-entrypoint | 0 | 3.10.0-r3 |
| Chainguard | kubeflow-jupyter-web-app | 0 | 1.10.0-r2 |
| Chainguard | kubeflow-volumes-web-app | 0 | 1.10.0-r1 |
| Chainguard | mlflow | 0 | 2.22.0-r2 |
| Chainguard | mlflow-bitnami | 0 | 2.22.0-r2 |
| Chainguard | mlflow-iamguarded-compat | 0 | 2.22.0-r2 |
| Chainguard | nemo | 0 | 2.3.0-r0 |
| Chainguard | pgadmin4 | 0 | 9.3-r1 |
| Chainguard | pgadmin4-oci-entrypoint | 0 | 9.3-r1 |
| Chainguard | pgadmin4-pg12 | 0 | 9.3-r1 |
| Chainguard | pgadmin4-pg13 | 0 | 9.3-r1 |
| Chainguard | pgadmin4-pg14 | 0 | 9.3-r1 |
| Chainguard | pgadmin4-pg15 | 0 | 9.3-r1 |
| Chainguard | pgadmin4-pg16 | 0 | 9.3-r1 |
| Chainguard | pgadmin4-pg17 | 0 | 9.3-r1 |
| Chainguard | py3.10-ambassador | 0 | 3.10.0-r3 |
| Chainguard | py3.11-ambassador | 0 | 3.10.0-r3 |
| Chainguard | py3.12-ambassador | 0 | 3.10.0-r3 |
| Chainguard | py3.13-ambassador | 0 | 3.10.0-r3 |
| Debian:13 | flask | 0 | No fix |
| Wolfi | airflow-3 | 0 | 3.0.1-r1 |
| Wolfi | airflow-3-bitnami-compat | 0 | 3.0.1-r1 |
| Wolfi | airflow-3-compat | 0 | 3.0.1-r1 |
| Wolfi | airflow-3-iamguarded-compat | 0 | 3.0.1-r1 |
| Wolfi | emissary | 0 | 3.10.0-r3 |
| Wolfi | emissary-apiext | 0 | 3.10.0-r3 |
| Wolfi | emissary-oci-entrypoint | 0 | 3.10.0-r3 |
| Wolfi | kubeflow-jupyter-web-app | 0 | 1.10.0-r2 |
| Wolfi | kubeflow-volumes-web-app | 0 | 1.10.0-r1 |
| Wolfi | mlflow | 0 | 2.22.0-r2 |
| Wolfi | mlflow-bitnami | 0 | 2.22.0-r2 |
| Wolfi | mlflow-iamguarded-compat | 0 | 2.22.0-r2 |
| Wolfi | py3.10-ambassador | 0 | 3.10.0-r3 |
| Wolfi | py3.11-ambassador | 0 | 3.10.0-r3 |
| Wolfi | py3.12-ambassador | 0 | 3.10.0-r3 |
| Wolfi | py3.13-ambassador | 0 | 3.10.0-r3 |
| openSUSE:Tumbleweed | python-Flask | 0 | 3.1.1-1.1 |
| pypi | Flask | 3.1.0 | No fix |
Related vulnerabilities
- CVE-2026-27205 Flask is a web server gateway interface (WSGI) web application framework. Also affects flask
- CVE-2026-34073 cryptography is a package designed to expose cryptographic primitives and recipes to… Also affects airflow-3
- CVE-2026-25645 Requests is a HTTP library. Also affects airflow-3
- CVE-2026-4539 A security flaw has been discovered in pygments up to 2.19.2. Also affects airflow-3
- CVE-2026-30922 pyasn1 is a generic ASN.1 library for Python. Also affects airflow-3
- CVE-2026-27448 pyOpenSSL is a Python wrapper around the OpenSSL library. Also affects airflow-3
- CVE-2026-27459 pyOpenSSL is a Python wrapper around the OpenSSL library. Also affects airflow-3
- CVE-2026-32597 PyJWT is a JSON Web Token implementation in Python. Also affects airflow-3