Description
Improper restriction of excessive authentication attempts (CWE-307) in pgAdmin 4.

pgAdmin enforces MAX_LOGIN_ATTEMPTS only inside its custom /authenticate/login view. Flask-Security's default /login view, which is registered automatically by security.init_app() and is reachable on every server, never consulted the User.locked field: 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 triggered an account lockout via /authenticate/login could therefore obtain a session by re-submitting valid credentials directly to /login, defeating the brute-force-protection control for accounts using the INTERNAL authentication source. The same bypass also means that login attempts via /login are never rate-limited, so an attacker can perform an unbounded online password-guessing attack against INTERNAL accounts regardless of MAX_LOGIN_ATTEMPTS.

Fix overrides User.is_active and User.is_locked() so the locked column is enforced on every authentication path. LDAP, OAuth2, Kerberos, and Webserver users are not reachable by this bypass because 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 (the /authenticate/login view filters by auth_source=INTERNAL).

This issue affects pgAdmin 4: before 9.15.
Published: 2026-05-11
Score: 6.9 Medium
EPSS: < 1% Very Low
KEV: No
Impact: n/a
Action: n/a
AI Analysis

Impact

Improper restriction of excessive authentication attempts (CWE‑307) in pgAdmin 4 enables an attacker to bypass the built‑in MAX_LOGIN_ATTEMPTS safeguard by exploiting the default Flask‑Security /login view. Because pgAdmin’s custom /authenticate/login endpoint applies the lockout but the automatically registered /login endpoint does not consult the User.locked flag, an account that has already been locked can still be accessed. An attacker who triggers a lockout via the protected endpoint can then replay valid credentials to /login, removing the lockout protection and permitting unlimited online password guessing against INTERNAL accounts.

Affected Systems

The vulnerability affects pgAdmin 4 prior to version 9.15, specifically for users authenticated with the INTERNAL authentication source. Users leveraging LDAP, OAuth2, Kerberos, or Webserver authentication are not impacted because they lack a local password and are rejected before the lockout check. Only installations of pgAdmin 4 before 9.15 that expose the default Flask‑Security /login route are vulnerable.

Risk and Exploitability

The CVSS base score is 6.9, indicating moderate severity, and the EPSS score is not published. The vulnerability is not listed in CISA KEV. The likely attack vector is remote, via the web interface, and requires network access to the pgAdmin server. An attacker can initiate a lockout via /authenticate/login and subsequently perform an unbounded online credential‑guessing walk on INTERNAL accounts through the unprotected /login endpoint. The absence of automatic rate limiting on this path can lead to rapid password enumeration.

Generated by OpenCVE AI on May 11, 2026 at 16:59 UTC.

Remediation

No vendor fix or workaround currently provided.

OpenCVE Recommended Actions

  • Upgrade pgAdmin 4 to version 9.15 or later so that lockout enforcement is applied to all authentication paths.
  • If upgrading must be delayed, restrict or disable the Flask‑Security /login endpoint to prevent the bypass from being usable.
  • Apply network‑level rate limiting or firewall rules to constrain the rate of credential‑guessing attempts against the pgAdmin web service.

Generated by OpenCVE AI on May 11, 2026 at 16:59 UTC.

Tracking

Sign in to view the affected projects.

Advisories

No advisories yet.

History

Tue, 12 May 2026 09:15:00 +0000

Type Values Removed Values Added
First Time appeared Pgadmin
Pgadmin pgadmin 4
Vendors & Products Pgadmin
Pgadmin pgadmin 4

Mon, 11 May 2026 16:15:00 +0000

Type Values Removed Values Added
Weaknesses CWE-307
Metrics ssvc

{'options': {'Automatable': 'yes', 'Exploitation': 'none', 'Technical Impact': 'partial'}, 'version': '2.0.3'}


Mon, 11 May 2026 15:30:00 +0000

Type Values Removed Values Added
Description Improper restriction of excessive authentication attempts (CWE-307) in pgAdmin 4. pgAdmin enforces MAX_LOGIN_ATTEMPTS only inside its custom /authenticate/login view. Flask-Security's default /login view, which is registered automatically by security.init_app() and is reachable on every server, never consulted the User.locked field: 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 triggered an account lockout via /authenticate/login could therefore obtain a session by re-submitting valid credentials directly to /login, defeating the brute-force-protection control for accounts using the INTERNAL authentication source. The same bypass also means that login attempts via /login are never rate-limited, so an attacker can perform an unbounded online password-guessing attack against INTERNAL accounts regardless of MAX_LOGIN_ATTEMPTS. Fix overrides User.is_active and User.is_locked() so the locked column is enforced on every authentication path. LDAP, OAuth2, Kerberos, and Webserver users are not reachable by this bypass because 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 (the /authenticate/login view filters by auth_source=INTERNAL). This issue affects pgAdmin 4: before 9.15.
Title pgAdmin 4: Account-lockout bypass via Flask-Security default /login view
References
Metrics cvssV3_1

{'score': 6.5, 'vector': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N'}

cvssV4_0

{'score': 6.9, 'vector': 'CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N'}


Subscriptions

Pgadmin Pgadmin 4
cve-icon MITRE

Status: PUBLISHED

Assigner: PostgreSQL

Published:

Updated: 2026-05-11T16:04:54.699Z

Reserved: 2026-05-04T21:27:01.217Z

Link: CVE-2026-7820

cve-icon Vulnrichment

Updated: 2026-05-11T16:04:27.131Z

cve-icon NVD

Status : Received

Published: 2026-05-11T16:17:39.497

Modified: 2026-05-11T17:16:35.473

Link: CVE-2026-7820

cve-icon Redhat

No data.

cve-icon OpenCVE Enrichment

Updated: 2026-05-12T09:00:06Z

Weaknesses