Summary
The current encryption scheme derives the Fernet key directly from the argon2 password hash stored in the database:
hashed_password = user['password']
key = base64.urlsafe_b64encode(hashed_password.encode("utf-8").ljust(32)[:32])
fernet = Fernet(key)
Since the password hash is stored server-side, anyone with database access (including the server operator of a public instance) can decrypt all user health data. The encryption effectively only protects against partial DB leaks where the users collection is not exposed.
Suggested approach
Move to client-side encryption (E2E) where the encryption key is derived on the device and never sent to the server. The server would only store and return opaque encrypted blobs.
This would require changes to both the API (/sync, /fetch) and the client app.
Impact
This primarily affects users of public instances who trust the server operator with their credentials but may not expect their health data to be readable by the operator.
🤖 Generated with Claude Code
Summary
The current encryption scheme derives the Fernet key directly from the argon2 password hash stored in the database:
Since the password hash is stored server-side, anyone with database access (including the server operator of a public instance) can decrypt all user health data. The encryption effectively only protects against partial DB leaks where the
userscollection is not exposed.Suggested approach
Move to client-side encryption (E2E) where the encryption key is derived on the device and never sent to the server. The server would only store and return opaque encrypted blobs.
This would require changes to both the API (
/sync,/fetch) and the client app.Impact
This primarily affects users of public instances who trust the server operator with their credentials but may not expect their health data to be readable by the operator.
🤖 Generated with Claude Code