6.9

CVE-2026-7820: pgAdmin 4: Account-lockout bypass via Flask-Security default /login view

Analyzed
AliasesGHSA-hv9p-2pqf-r5w3PYSEC-2026-2869CGA-7wcq-q333-q7q3
Published 11-05-2026Last modified 11-05-2026

Vulnerability summary

CVE-2026-7820 is a medium (CVSS 6.9) vulnerability in pgadmin pgadmin_4. EPSS estimates a 0.21% chance of exploitation in the next 30 days, higher than 11.3% of scored vulnerabilities.

Priority
Routine

Not severe (CVSS 6.9, network access); no exploitation reported by the 5 checked sources

Source freshness unavailable

How is this decided?
CVSS score
6.9/10
010
Medium · v4.0 (CVE.org)
EPSS score
0.21%
0%100%
Low · -0.11 pp in 30 days
KEVNot listedNot listed by any tracked catalog.
RansomwareNot flaggedNo ransomware use recorded.
Public exploits0No public exploits recorded

Advisory lineage

Upstream 0 · Downstream 1 · Related 2

Timeline

  1. 11-05-2026
    PublishedVulnerability first disclosed.
  2. 11-05-2026
    Last modifiedVulnerability information updated.

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.

CVSS metrics

7 scores · 4 sources · 2 versions

EPSS trend

Probability

0.21%

Chance of exploitation in the next 30 days

Percentile

11%

Versus all other CVEs

30-day change

Decrease -0.11 pp

From 0.33% on 04-10-2026

04-10-202603-11-2026

Known exploited

Compare KEV catalogs
CISA KEV

Not in the CISA KEV catalog.

ENISA CNW

Not in the ENISA CNW catalog.

CIRCL

Not in the CIRCL catalog.

Public exploits

0 found

No public exploits indexed.

Weaknesses

CWE · root cause

Affected systems

Version check

Known conditions: network-reachable, no authentication, no user interaction (CVSS vector). Other conditions: not stated in public data.

Chainguard1 product
  • pgadmin4< 9.15-r1 | < 9.15-r0
Pgadmin1 product
Pgadmin.org1 product
PyPI1 product
  • pgadmin4< 9.15

4 vendors · 4 products

References

7 links