PatchSiren cyber security CVE debrief
CVE-2026-7820 pgadmin.org CVE debrief
pgAdmin 4 versions prior to 9.15 contain an authentication bypass vulnerability in the account lockout mechanism. The application enforces MAX_LOGIN_ATTEMPTS only within its custom /authenticate/login view, while Flask-Security's default /login view—automatically registered and reachable on every server—fails to consult the User.locked field. This occurs because pgAdmin's User model relied on Flask-Security's UserMixin.is_locked() (which always returns 'not locked') and Flask-Login's is_active (which only checks the active column, not locked). An attacker who triggers an account lockout via /authenticate/login can obtain a session by re-submitting valid credentials directly to /login, defeating brute-force protection for INTERNAL authentication source accounts. Additionally, login attempts via /login are never rate-limited, enabling unbounded online password-guessing attacks against INTERNAL accounts regardless of MAX_LOGIN_ATTEMPTS. The fix overrides User.is_active and User.is_locked() to ensure the locked column is enforced on every authentication path. LDAP, OAuth2, Kerberos, and Webserver users are not affected by this bypass as they have no local password and are rejected by Flask-Security's LoginForm.validate before the locked check; the lockout itself is also internal-only.
- Vendor
- pgadmin.org
- Product
- pgAdmin 4
- CVSS
- MEDIUM 6.9
- CISA KEV
- Not listed in stored evidence
- Original CVE published
- 2026-05-11
- Original CVE updated
- 2026-05-26
- Advisory published
- 2026-05-11
- Advisory updated
- 2026-05-26
Who should care
Organizations running pgAdmin 4 with INTERNAL authentication enabled; security teams responsible for database administration tool hardening; compliance officers monitoring brute-force protection controls
Technical summary
The vulnerability stems from inconsistent enforcement of account lockout state across authentication endpoints in pgAdmin 4. The custom /authenticate/login view implements MAX_LOGIN_ATTEMPTS and sets User.locked, but Flask-Security's default /login view—registered via security.init_app()—bypasses this check because User.is_locked() inherited from UserMixin always returns False and User.is_active only checks the active column. The fix modifies the User model to override both methods, ensuring locked status is evaluated regardless of which endpoint processes the authentication request. This is a logic flaw in the integration between pgAdmin's custom authentication layer and Flask-Security's default behavior, not a vulnerability in Flask-Security itself.
Defensive priority
HIGH
Recommended defensive actions
- Upgrade pgAdmin 4 to version 9.15 or later to obtain the fix that enforces account lockout on all authentication paths
- If immediate patching is not possible, restrict network access to pgAdmin 4 administrative interfaces to trusted source IP addresses
- Monitor authentication logs for anomalous patterns including rapid sequential login attempts followed by successful authentication from the same source
- Review user accounts configured with INTERNAL authentication source for unauthorized access indicators
- Consider implementing additional network-layer rate limiting on pgAdmin 4 endpoints as a compensating control
- Verify that external authentication sources (LDAP, OAuth2, Kerberos, Webserver) remain properly configured and are not inadvertently fallback options
Evidence notes
Vulnerability description and fix details derived from NVD record published 2026-05-11 and modified 2026-05-26. Affected versions confirmed as pgAdmin 4 before 9.15 per CPE criteria. Vendor advisory and patch available via GitHub issue #9904.
Official resources
-
CVE-2026-7820 CVE record
CVE.org
-
CVE-2026-7820 NVD detail
NVD
-
Source item URL
nvd_modified
-
Mitigation or vendor reference
f86ef6dc-4d3a-42ad-8f28-e6d5547a5007 - Issue Tracking, Patch, Vendor Advisory
2026-05-11