CVE-2025-58065 Overview
CVE-2025-58065 is an authentication weakness in Flask-AppBuilder, a Python application development framework built on Flask. Versions prior to 4.8.1 register the password reset endpoint regardless of the configured authentication backend. When administrators configure OAuth, LDAP, or another non-database authentication method, the reset routes remain accessible even though they are hidden in the UI. An enabled user can reset their local password and mint JSON Web Tokens (JWTs), retaining access after being disabled at the upstream identity provider. The flaw maps to Improper Authentication [CWE-287].
Critical Impact
Users disabled at an external identity provider can retain application access by resetting their local password and generating valid JWT tokens, breaking the integrity of centralized identity governance.
Affected Products
- Flask-AppBuilder versions prior to 4.8.1
- Deployments configured with AUTH_OAUTH, AUTH_LDAP, AUTH_OID, or AUTH_REMOTE_USER
- Applications built on Flask-AppBuilder that expose JWT token issuance
Discovery Timeline
- 2025-09-11 - CVE-2025-58065 published to the National Vulnerability Database
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2025-58065
Vulnerability Analysis
Flask-AppBuilder registers views during security manager initialization. Prior to version 4.8.1, ResetPasswordView and ResetMyPasswordView were registered unconditionally via add_view_no_menu, regardless of the value of AUTH_TYPE. Although the UI links to these views are only rendered when AUTH_DB is active, the underlying HTTP routes remain reachable at their default URLs.
In deployments that use external identity providers, an authenticated user can invoke the reset endpoint to change their locally stored password hash. If the account is later disabled at the identity provider, the attacker can still authenticate through any database-backed path that consults the local password, including endpoints that issue JWTs. This defeats the centralized deprovisioning workflow security teams rely on when using single sign-on.
Root Cause
The root cause is a missing conditional guard around view registration in flask_appbuilder/security/manager.py. View registration for the password reset routes did not check self.auth_type == AUTH_DB before being attached to the application, leaving the routes registered for all authentication backends.
Attack Vector
Exploitation requires an authenticated session belonging to an enabled application user. The attacker navigates directly to the hidden reset URL, submits a new password, and subsequently uses the local credential to obtain a JWT even after the identity provider has revoked their account.
if self.registeruser_view:
self.appbuilder.add_view_no_menu(self.registeruser_view)
- self.appbuilder.add_view_no_menu(self.resetpasswordview())
- self.appbuilder.add_view_no_menu(self.resetmypasswordview())
self.appbuilder.add_view_no_menu(self.userinfoeditview())
if self.auth_type == AUTH_DB:
self.user_view = self.userdbmodelview
self.auth_view = self.authdbview()
+ self.appbuilder.add_view_no_menu(self.resetpasswordview())
+ self.appbuilder.add_view_no_menu(self.resetmypasswordview())
elif self.auth_type == AUTH_LDAP:
self.user_view = self.userldapmodelview
# Source: https://github.com/dpgaspar/Flask-AppBuilder/commit/a942a9cc5775752f9a02f97fd8198dd288fa93ee
The patch moves the two add_view_no_menu calls inside the AUTH_DB branch so the reset routes are only registered when database authentication is active.
Detection Methods for CVE-2025-58065
Indicators of Compromise
- HTTP requests to /resetmypassword/form or /resetpassword/form in applications configured with non-database authentication backends
- Successful password reset events for users who authenticate exclusively through OAuth, LDAP, or OIDC
- JWT tokens issued to accounts that have been disabled at the upstream identity provider
Detection Strategies
- Correlate reset endpoint access with the value of AUTH_TYPE in the Flask-AppBuilder configuration; any hits when AUTH_TYPE != AUTH_DB warrant investigation
- Compare application login and token issuance events against identity provider deprovisioning events to identify users authenticating after account disablement
- Alert on password change events for user records whose login_count for the database path is zero prior to the reset
Monitoring Recommendations
- Enable verbose access logging on the reverse proxy for all URLs matching resetpassword and resetmypassword
- Forward Flask-AppBuilder audit logs and identity provider events to a central analytics platform for cross-source correlation
- Track version metadata for deployed Flask-AppBuilder instances to identify hosts still running versions prior to 4.8.1
How to Mitigate CVE-2025-58065
Immediate Actions Required
- Upgrade Flask-AppBuilder to version 4.8.1 or later across all environments
- Audit user accounts for unexpected local password changes since deployment of non-database authentication
- Rotate or invalidate existing JWT signing keys if evidence of exploitation is found, forcing token reissuance
Patch Information
The fix is delivered in Flask-AppBuilder v4.8.1 via pull request #2384 and commit a942a9cc. Additional context is available in the GitHub Security Advisory GHSA-765j-9r45-w2q2.
Workarounds
- Manually unregister the reset password routes in application startup code when AUTH_TYPE is not AUTH_DB
- Block access to /resetpassword and /resetmypassword URLs at the reverse proxy, web application firewall, or ingress controller
- Implement identity provider webhook processing that removes disabled users from the Flask-AppBuilder ab_user table
# Example NGINX block for non-AUTH_DB deployments
location ~* ^/(resetpassword|resetmypassword) {
return 403;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

