CVE-2026-55164

MEDIUMPre-NVD 4.94.9
EchelonGraph scoreLOW confidence

This medium-severity CVE scores 4.9 under the CNA's CVSS (NVD's own analysis pending). EPSS exploit-prediction score not yet available (the EPSS model rescores nightly; freshly-published CVEs typically appear within 48 hours). GitHub Security Advisory data not yet ingested — confidence will rise once GHSA publishes (typical lag: hours to days for open-source ecosystem CVEs; never for infrastructure-only CVEs).

Triggered by: NVD CVSS baseline
Sources: cna:github_m
4.9
EchelonGraph verdictMonitorLow exploitation likelihood right now — keep watching.
  • Lower severity and no public exploit yet
CISA-KEV: Not listedEPSS: CVSS: 4.9Exploit: NoneExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

Lemur user-update path stores plaintext passwords

Summary

lemur.users.service.update() writes a user's new password as plaintext to the users.password column. The User model wires bcrypt hashing to SQLAlchemy's before_insert event but registers no equivalent listener for before_update, and service.update() does not call user.hash_password() after assigning the new value. Every password change performed through the admin-gated PUT /api/1/users/ endpoint persists the user's password to the database in cleartext.

Root Cause

lemur/users/models.py:

# line 38
class User(BaseModel):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    password = Column(String(128))            # plain column, no setter, no Vault descriptor

line 74

def hash_password(self): if self.password: self.password = bcrypt.generate_password_hash(self.password).decode("utf-8")

line 111

listen(User, "before_insert", hash_password) # only before_insert is wired

lemur/users/service.py:

# line 46
def update(user_id, username, email, active, profile_picture, roles, password=None):
    ...
    user = get(user_id)
    user.username = username
    user.email = email
    user.active = active
    user.profile_picture = profile_picture
    if password:
        user.password = password              # raw assignment
    update_roles(user, roles)
    return database.update(user)              # commits, no hashing

No before_update listener exists. User.password is a plain Column(String(128)) with no property setter that hashes on assignment. The bcrypt code path is bypassed entirely on every UPDATE statement that touches this column.

Affected Endpoints

| Method | Path | Source | |---|---|---| | PUT | /api/1/users/` | lemur/users/views.py:274 (gated by @admin_permission.require) |

lemur/auth/views.py:323 also calls user_service.update() during SSO/OAuth login, but passes only six positional arguments. password defaults to None on that path and the if password: guard short-circuits. The bug is triggered only through the admin-only PUT handler.

Impact

When an administrator changes a user's password via PUT /api/1/users/, the cleartext password is persisted to users.password. Subsequent login attempts for that user will fail (check_password calls bcrypt.check_password_hash against an unhashed value), pushing operators toward workarounds.

The more serious consequence is a defense-in-depth bypass. Bcrypt is the protection that prevents a database compromise from yielding usable credentials. With plaintext rows present, an attacker who exfiltrates the users table, a backup, a read replica, or query logs obtains directly usable login credentials — no offline cracking required. Because users reuse passwords across services, the blast radius extends beyond Lemur.

The bug specifically affects admin-driven password resets, which are the normal post-incident workflow and exactly when plaintext storage is most harmful.

Steps to Reproduce

  • Install Lemur with default config. Create an admin user and a target user 'alice' (created via the standard flow, password will be hashed correctly on insert).
  • Verify the initial hash:
psql lemur -c "SELECT password FROM users WHERE username='alice';" # Output: $2b$12$N9Q... (bcrypt hash, as expected)
  • As admin, change alice's password via the API:
curl -X PUT https://lemur.local/api/1/users/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "username": "alice", "email": "[email protected]", "active": true, "profile_picture": null, "roles": [{"name": "operator"}], "password": "ProofOfConcept_2026" }'
  • Read the column again:
psql lemur -c "SELECT password FROM users WHERE username='alice';" # Output: ProofOfConcept_2026 ← plaintext, not hashed
  • Confirm the failure mode: 'alice' can no longer log in with 'ProofOfConcept_2026'
because check_password runs bcrypt.check_password_hash() against the cleartext column.

Remediation

Register the listener for both events:

# lemur/users/models.py
listen(User, "before_insert", hash_password)
listen(User, "before_update", hash_password)

Alternative, equivalent fix in the service layer:

# lemur/users/service.py, in update()
    if password:
        user.password = password
        user.hash_password()

The listener fix is preferred because it closes the gap for any future code path that mutates user.password.

A one-time migration is recommended to detect and re-hash any rows already stored in cleartext. Bcrypt hashes begin with $2b$, $2a$, or $2y$`. Any cleartext credential should be treated as compromised — rotate it, do not just re-hash it — since it has been at rest in plaintext and may exist in backups, audit logs, and replicas.

CVSS v3
4.9
EG Score
4.9(low)
EPSS
KEV
Not listed

Published

June 25, 2026

Last Modified

June 25, 2026

Vendor Advisories for CVE-2026-55164(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Data Freshness Timeline

(refreshed 7× in last 7d / 11× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-07-06 15:32 UTCEG score recompute
  2. 2026-07-05 13:53 UTCEG score recompute
  3. 2026-07-04 12:15 UTCEG score recompute
  4. 2026-07-03 10:36 UTCEG score recompute
  5. 2026-07-02 08:49 UTCEG score recompute
  6. 2026-07-01 07:10 UTCEG score recompute
  7. 2026-06-30 05:32 UTCEG score recompute
  8. 2026-06-29 03:51 UTCEG score recompute
  9. 2026-06-28 02:04 UTCEG score recompute
  10. 2026-06-27 00:25 UTCEG score recompute
  11. 2026-06-25 22:46 UTCEG score recompute

Frequently asked(4)

What is CVE-2026-55164?
CVE-2026-55164 is a medium vulnerability published on June 25, 2026. Lemur user-update path stores plaintext passwords Summary lemur.users.service.update() writes a user's new password as plaintext to the users.password column. The User model wires bcrypt hashing to SQLAlchemy's beforeinsert event but registers no equivalent listener for beforeupdate, and…
When was CVE-2026-55164 disclosed?
CVE-2026-55164 was first published in the National Vulnerability Database on June 25, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
What is the CVSS score of CVE-2026-55164?
CVE-2026-55164 has a CVSS v4.0 base score of 4.9 (CNA self-assessment; NVD's own analysis pending). The EG score is currently aggregating — additional source signals are being incorporated as they become available..
How do I remediate CVE-2026-55164?
Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-55164, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

Dependency Blast Radius

Explore the affected products and dependency analysis for CVE-2026-55164

Explore →

Is Your Infrastructure Affected by CVE-2026-55164?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.