Plain text user password leakage

Created on 4 May 2017, over 7 years ago
Updated 17 September 2024, about 1 month ago

This issue was discussed by the Drupal Security Team, and their decision was that this can be solved in a public issue.

Problem/Motivation

There are instances where a plaintext password leaks beyond the user system forms.

The user register form calls user_register_submit(). That will call entity_form_submit_build_entity(). This builds a user object from the form values, and will set ->pass to the plaintext password. That will also call field_attach_submit(), which will invoke hook_field_attach_submit() and receive the user $entity with the plaintext password

This means that anything that implements or is called from a hook_field_attach_submit() can potentially get a plaintext password during user submission before the actual user is saved (and the password is hashed). A similar path happens when changing a password, both user initiated or admin initiated.

In order to leverage this leakage, an attacker must be able to install code on the system. However, if an attacker can install code on the system, they can already exploit the system in countless ways. In addition, this is similar to how a plaintext password can be obtained by using a form_alter to add an additional validator to the user forms.

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Needs work

Version

7.0 ⚰️

Component
BaseΒ  β†’

Last updated about 4 hours ago

Created by

πŸ‡ΊπŸ‡ΈUnited States mpdonadio Philadelphia/PA/USA (UTC-5)

Live updates comments and jobs are added and updated live.
  • Security improvements

    It makes Drupal less vulnerable to abuse or misuse. Note, this is the preferred tag, though the Security tag has a large body of issues tagged to it. Do NOT publicly disclose security vulnerabilities; contact the security team instead. Anyone (whether security team or not) can apply this tag to security improvements that do not directly present a vulnerability e.g. hardening an API to add filtering to reduce a common mistake in contributed modules.

  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • First commit to issue fork.
  • Merge request !9492Moving 2875722-11 to gitlab β†’ (Open) created by akalata
  • πŸ‡ΊπŸ‡ΈUnited States akalata

    @hgoto Hashing the value of the submitted password at the earliest possible time is important because it lessens the window of opportunity for the value to get accidentally exposed when writing serialized data to a log file or the watchdog error table. With this change, we can at least prevent having an unhashed password as part of the created user entity before user_save is called.

    I did notice a concerning but unused set of code that implies the sending of passwords via email in plain-text, but I'm guessing that this is quite old and was just not removed when the support for sending the password in the welcome email was removed.

    // Add plain text password into user account to generate mail tokens.
    $account->password = $pass;
    
  • Pipeline finished with Success
    about 1 month ago
    Total: 426s
    #282592
  • Status changed to Needs work about 1 month ago
  • πŸ‡ΈπŸ‡°Slovakia poker10

    Thanks for working on this.

    Re #15: Yes, Drupal core removed the support for sending passwords in registration emails here: #660302: Migration path for changed user email tokens; don't complicate translation of default messages β†’ . However, there are some contrib modules still using this, so we need to be careful and not break these. For example:

    LoginToboggan (https://git.drupalcode.org/project/logintoboggan, "provide a user:password token that can be used to send a plain text password as part of registration process.")

    Registration Password Token ( https://www.drupal.org/project/rpt β†’ )

    ... (I have not done a full search for such modules) ...

    -----

    I think the one important point in the parent issue was to remove the plaintext password from the user object, so that it cannot be accidentally serialized/written to the database. If we change it in the form_state, then we are probably going to break multistep forms, some contrib modules, etc., which I think is not something we can do in this D7 phase.

    Also, the MR is making changes to user_register_submit(), but what about user_profile_form_submit()?

    Third thing - we are still saving the plaintext value to the $account object in user_register_submit(), see:

      // Add plain text password into user account to generate mail tokens.
      $account->password = $pass;
    

    Other than that, the MR is also missing additional tests, which we will need before a commit, so given these points, I am changing the status back to Needs Work. Thanks!

  • Status changed to RTBC about 1 month ago
  • πŸ‡ΊπŸ‡ΈUnited States akalata
  • πŸ‡ΈπŸ‡°Slovakia poker10

    @akalata Can you explain the status change with regards to my questions raised in #16? Also why have you removed the "Needs tests" tag. Thanks!

  • Status changed to Needs work about 1 month ago
  • πŸ‡ΊπŸ‡ΈUnited States akalata

    @poker10 I hadn't refreshed the page to see your comment and the additional tag. reverted.

  • πŸ‡ΊπŸ‡ΈUnited States akalata

    @poker10 I'm a bit confused by your feedback regarding the plain-text password at `$account->password = $pass;`, which I called out in #15. First you say that it's necessary to support contrib module tokens, but then you mention it as your "third thing" which makes it sound like something that needs to be changed?

    If we don't want these changes in `$form_state`, for the reason that you've mentioned above, is there a recommended alternative? Seems like we would need to add a try/catch to every function that accepts $account or $form_state, and clear the password value before throwing any exceptions:

    • entity_form_submit_build_entity()
    • user_save()
    • entity_uri()
    • _user_mail_notify()
    • user_login_submit()
    • form_state_values_clean()

    Given the level of disruption THAT might cause, is this worth even attempting?

  • πŸ‡ΈπŸ‡°Slovakia poker10

    @akalata By my comment about the "third thing" I meant that the MR is hashing the password to $form_state['values']['pass'], but the password is still saved to $account->password in a plaintext. So I was not sure about the benefit of the solution, if we still keep the plaintext password on another place. I will try to take a look at this, what other possible solutions we have here. Thanks!

Production build 0.71.5 2024