--- title: "1.31.5 — Account save and realtime write hardening" description: "Closes account-save and realtime paths that could overwrite authentication secrets, sign-in identities, API keys, and protected account metadata." date: "2026-10-01" tags: ["release"] canonical: "https://django-mojo.sitesmojo.com/changelog/1-31-5/" --- Closes account-save and realtime paths that could overwrite authentication secrets, sign-in identities, API keys, and protected account metadata. ### Security - A stored one-time code can no longer be written through an account save. A signed-in user could set their own phone or email verification code, and an administrator with `manage_users` could set a sign-in code on another account. - An account save can no longer replace or switch off an authenticator through a nested `totp` record. - The undocumented `permanent_password` key no longer sets a password. A user's own change still needs the current password, and an administrator's reset through `new_password` is unchanged. - A field a model declares unwritable can no longer be written through its column alias, such as `user_id` for `user`. An administrator could move a personal API key or a sign-in connection to another account and then sign in as that account. - An administrator can no longer change the provider identity of a sign-in connection. - A personal API key's signing secret, and the stored tokens of sign-in connections and group API keys, can no longer be written through a save. - The realtime `set_meta` message is removed. Any signed-in socket could overwrite account metadata, including the protected section. ### Changed - Releases publish a wheel only. No source archive is uploaded. ### Upgrade notes - A client that sent `set_meta` over the websocket now gets a plain acknowledgement and nothing is written. Save account metadata through the REST API. - Posting a blocked key is ignored without an error: `secrets`, `permanent_password`, a nested `totp`, or a sign-in connection's `provider`, `provider_uid`, `email` or `user_id`. - In your own models, a foreign key listed in `NO_SAVE_FIELDS` now also refuses its `_id` alias.