Observable Response Discrepancy in Flask-AppBuilder
Description
Flask-AppBuilder is an application development framework, built on top of the Flask web framework. In affected versions there exists a user enumeration vulnerability. This vulnerability allows for a non authenticated user to enumerate existing accounts by timing the response time from the server when you are logging in. Users are advised to upgrade to version 3.4.4 as soon as possible. There are no known workarounds for this issue.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Flask-AppBuilder versions before 3.4.4 allow non-authenticated users to enumerate existing accounts via response time variations during login.
Vulnerability
Flask-AppBuilder, an application development framework built on Flask, contains a user enumeration vulnerability in its authentication mechanism. In versions prior to 3.4.4, the server response time differs when a login attempt is made for an existing account versus a non-existing one, allowing an attacker to infer valid usernames [1][2]. This affects all installations using the default login endpoint.
Exploitation
An attacker sends login requests (e.g., via HTTP POST to the /login/ endpoint) with various usernames and measures the response time. No authentication or prior access is required. The timing discrepancy enables the attacker to distinguish between existing and non-existing accounts [1][2].
Impact
Successful exploitation reveals valid usernames, which can then be targeted for password guessing, credential stuffing, or social engineering attacks. The vulnerability does not expose passwords or other sensitive data directly but weakens the authentication layer [1][2].
Mitigation
Users should upgrade to Flask-AppBuilder version 3.4.4 or later, which fixes the timing discrepancy by updating user.last_login only after successful authentication [4]. No workarounds are available for earlier versions [1][2].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
Flask-AppBuilderPyPI | < 3.4.4 | 3.4.4 |
Affected products
2- Flask-AppBuilder/Flask-AppBuilderdescription
Patches
1e2b744c258fffix: Only update user.last_login on successful authentication (#1775)
2 files changed · +78 −4
flask_appbuilder/security/manager.py+9 −4 modified@@ -820,23 +820,28 @@ def reset_password(self, userid, password): def update_user_auth_stat(self, user, success=True): """ - Update authentication successful to user. + Update user authentication stats upon successful/unsuccessful + authentication attempts. :param user: - The authenticated user model + The identified (but possibly not successfully authenticated) user + model :param success: - Default to true, if false increments fail_login_count on user model + :type success: bool or None + Defaults to true, if true increments login_count, updates + last_login, and resets fail_login_count to 0, if false increments + fail_login_count on user model. """ if not user.login_count: user.login_count = 0 if not user.fail_login_count: user.fail_login_count = 0 if success: user.login_count += 1 + user.last_login = datetime.datetime.now() user.fail_login_count = 0 else: user.fail_login_count += 1 - user.last_login = datetime.datetime.now() self.update_user(user) def auth_user_db(self, username, password):
flask_appbuilder/tests/security/test_base_security_manager.py+69 −0 added@@ -0,0 +1,69 @@ +import datetime +import unittest +from unittest.mock import MagicMock, patch + +from flask_appbuilder.security.manager import BaseSecurityManager + + +@patch.object(BaseSecurityManager, "update_user") +@patch.object(BaseSecurityManager, "__init__", return_value=None) +class BaseSecurityManagerUpdateUserAuthStatTestCase(unittest.TestCase): + def test_first_successful_auth(self, mock1, mock2): + bsm = BaseSecurityManager() + + user_mock = MagicMock() + user_mock.login_count = None + user_mock.fail_login_count = None + user_mock.last_login = None + + bsm.update_user_auth_stat(user_mock, success=True) + + self.assertEqual(user_mock.login_count, 1) + self.assertEqual(user_mock.fail_login_count, 0) + self.assertEqual(type(user_mock.last_login), datetime.datetime) + self.assertTrue(bsm.update_user.called_once) + + def test_first_unsuccessful_auth(self, mock1, mock2): + bsm = BaseSecurityManager() + + user_mock = MagicMock() + user_mock.login_count = None + user_mock.fail_login_count = None + user_mock.last_login = None + + bsm.update_user_auth_stat(user_mock, success=False) + + self.assertEqual(user_mock.login_count, 0) + self.assertEqual(user_mock.fail_login_count, 1) + self.assertEqual(user_mock.last_login, None) + self.assertTrue(bsm.update_user.called_once) + + def test_subsequent_successful_auth(self, mock1, mock2): + bsm = BaseSecurityManager() + + user_mock = MagicMock() + user_mock.login_count = 5 + user_mock.fail_login_count = 9 + user_mock.last_login = None + + bsm.update_user_auth_stat(user_mock, success=True) + + self.assertEqual(user_mock.login_count, 6) + self.assertEqual(user_mock.fail_login_count, 0) + self.assertEqual(type(user_mock.last_login), datetime.datetime) + self.assertTrue(bsm.update_user.called_once) + + def test_subsequent_unsuccessful_auth(self, mock1, mock2): + bsm = BaseSecurityManager() + + user_mock = MagicMock() + user_mock.login_count = 5 + user_mock.fail_login_count = 9 + user_mock.last_login = None + + bsm.update_user_auth_stat(user_mock, success=False) + + self.assertEqual(user_mock.login_count, 5) + self.assertEqual(user_mock.fail_login_count, 10) + self.assertEqual(user_mock.last_login, None) + self.assertTrue(bsm.update_user.called_once)
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-wfjw-w6pv-8p7fghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-21659ghsaADVISORY
- github.com/dpgaspar/Flask-AppBuilder/commit/e2b744c258ff62ece9d5ac7172c3b4644ff4c2feghsaWEB
- github.com/dpgaspar/Flask-AppBuilder/commits/v3.4.4ghsaWEB
- github.com/dpgaspar/Flask-AppBuilder/pull/1775ghsax_refsource_MISCWEB
- github.com/dpgaspar/Flask-AppBuilder/security/advisories/GHSA-wfjw-w6pv-8p7fghsax_refsource_CONFIRMWEB
- github.com/pypa/advisory-database/tree/main/vulns/flask-appbuilder/PYSEC-2022-24.yamlghsaWEB
News mentions
0No linked articles in our index yet.