Visit Website →

Recent Items

fkie_cve-2026-55164

Lemur manages TLS certificate creation. Prior to 1.9.2, lemur.users.service.update assigned a replacement password directly to users.password, while lemur/users/models.py registered User.hash_password only for the before_insert event. Because no before_update listener ran, administrator-initiated password changes through PUT /api/1/users/ were committed as plaintext. The affected user could no longer authenticate normally because bcrypt verification received an unhashed value. A database, backup, replica, query-log, or administrative read compromise exposed immediately usable credentials without offline cracking. The fix registers hashing for before_update and avoids rehashing values that already have a bcrypt prefix. This issue is fixed in version 1.9.2.

Updated on 2026-10-07T04:07:34.579417+00:00

GHSA-q437-g7fv-2jvv — Lemur user-update path stores plaintext passwords

Affected: PyPI: lemur

## 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/<id>` endpoint persists the user's password to the database in cleartext.

## Root Cause

`lemur/users/models.py`:

```python # 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`:

```python # 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.pas…

Updated on 2026-10-07T04:07:34.579524+00:00

PYSEC-2026-2587 — Lemur user-update path stores plaintext passwords

Affected: PyPI: lemur

## 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/<id>` endpoint persists the user's password to the database in cleartext.

## Root Cause

`lemur/users/models.py`:

```python # 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`:

```python # 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.pas…

Updated on 2026-10-07T04:07:34.579652+00:00