CWE-620, Unverified Password Change, is what happens when setting a new password does not require the original password or any other form of authentication. It hits any product with user accounts, from web apps to router admin pages.
How it happens
A change-password endpoint accepts a new password and a user identifier. It checks that a session exists but not that the person behind it knows the current secret. If the user ID is in the request, an attacker can swap it for another account's.
# Vulnerable: no proof of the current password
@app.post("/change-password")
def change_password():
user = User.get(request.form["user_id"])
user.set_password(request.form["new_password"])
# Fixed: verify the old password for the logged-in user
@app.post("/change-password")
@login_required
def change_password():
user = current_user
if not user.check_password(request.form["old_password"]):
abort(403)
user.set_password(request.form["new_password"])
MITRE's observed cases include a router web interface that allowed an unverified password change (CVE-2025-4903), and web apps that let remote attackers change passwords of arbitrary users without the original password.
What an attacker gains
The record lists bypassing a protection mechanism and gaining privileges or assuming identity. An attacker who changes someone's password owns that account and everything it can do.
How to find it
The record lists no detection methods. Test it directly: change a password while logged in and see whether the old password is requested, then replay the request with another user's identifier. Review every code path that writes a password.
How to fix it
From MITRE:
- When prompting for a password change, force the user to provide the original password in addition to the new one.
- Do not use "forgotten password" functionality. If you must, make sure you only provide information to the actual user, for example through an email address or challenge question the legitimate user provided in the past. Do not allow the current user to change this identity information until the correct password has been provided.
A closer look at the recovery path
Password change is only one door. The record's second mitigation points at the other: the forgotten password flow. A reset link or code proves the person controls an email address, not that they know the password. That is acceptable only if the address on file was provided earlier by the legitimate user.
This is why MITRE says not to let the current user change the identity information used for recovery until the correct password has been provided. Otherwise an attacker with a brief foothold, such as an unattended browser, swaps the recovery email, resets the password and locks the owner out for good.
Think of each account change in tiers. Changing a display name needs a session. Changing a password, an email address or a recovery question should need a fresh proof of identity.
Related weaknesses on this site, such as weak recovery mechanisms, cover the next layer: how the reset itself should be protected once you decide to offer it.
Review checklist for your own product:
- Does every password write require the old password or a fresh proof of identity?
- Does the request take the target user from the session, never from a form field?
- Are recovery email addresses and questions protected by the same rule?
- Is the user told, by email, when the password changes?
The last item is a general good practice rather than a MITRE item, but it shortens the time an account takeover goes unnoticed.
Quick check
What must a password change request include?
The original password, or another form of authentication, along with the new one.