Security: Add the SensitiveParameter attribute to sensitive parameters.

Values passed to parameters with this attribute will be redacted if present in a stack trace when using PHP 8.2 or later. This reduces the chance that passwords and security keys get accidentally exposed in debug logs and bug reports.

Props petitphp, TobiasBg, jrf, johnbillion.

Fixes #57304
Built from https://develop.svn.wordpress.org/trunk@59754


git-svn-id: http://core.svn.wordpress.org/trunk@59096 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
John Blackbourn
2025-02-03 19:52:24 +00:00
parent ec037b17fa
commit b765f8b44c
11 changed files with 179 additions and 30 deletions

View File

@@ -195,7 +195,13 @@ class WP_Importer {
* @param bool $head
* @return array
*/
public function get_page( $url, $username = '', $password = '', $head = false ) {
public function get_page(
$url,
$username = '',
#[\SensitiveParameter]
$password = '',
$head = false
) {
// Increase the timeout.
add_filter( 'http_request_timeout', array( $this, 'bump_request_timeout' ) );

View File

@@ -44,7 +44,16 @@ if ( ! function_exists( 'wp_install' ) ) :
* @type string $password_message The explanatory message regarding the password.
* }
*/
function wp_install( $blog_title, $user_name, $user_email, $is_public, $deprecated = '', $user_password = '', $language = '' ) {
function wp_install(
$blog_title,
$user_name,
$user_email,
$is_public,
$deprecated = '',
#[\SensitiveParameter]
$user_password = '',
$language = ''
) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.6.0' );
}
@@ -563,7 +572,13 @@ if ( ! function_exists( 'wp_new_blog_notification' ) ) :
* @param string $password Administrator's password. Note that a placeholder message is
* usually passed instead of the actual password.
*/
function wp_new_blog_notification( $blog_title, $blog_url, $user_id, $password ) {
function wp_new_blog_notification(
$blog_title,
$blog_url,
$user_id,
#[\SensitiveParameter]
$password
) {
$user = new WP_User( $user_id );
$email = $user->user_email;
$name = $user->user_login;

View File

@@ -459,7 +459,10 @@ class WP_Application_Passwords {
* @param string $raw_password The raw application password.
* @return string The chunked password.
*/
public static function chunk_password( $raw_password ) {
public static function chunk_password(
#[\SensitiveParameter]
$raw_password
) {
$raw_password = preg_replace( '/[^a-z\d]/i', '', $raw_password );
return trim( chunk_split( $raw_password, 4, ' ' ) );

View File

@@ -285,7 +285,11 @@ class wp_xmlrpc_server extends IXR_Server {
* @param string $password User's password.
* @return WP_User|false WP_User object if authentication passed, false otherwise.
*/
public function login( $username, $password ) {
public function login(
$username,
#[\SensitiveParameter]
$password
) {
if ( ! $this->is_enabled ) {
$this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.' ) ) );
return false;
@@ -330,7 +334,11 @@ class wp_xmlrpc_server extends IXR_Server {
* @param string $password User's password.
* @return bool Whether authentication passed.
*/
public function login_pass_ok( $username, $password ) {
public function login_pass_ok(
$username,
#[\SensitiveParameter]
$password
) {
return (bool) $this->login( $username, $password );
}

View File

@@ -749,7 +749,13 @@ class wpdb {
* @param string $dbname Database name.
* @param string $dbhost Database host.
*/
public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
public function __construct(
$dbuser,
#[\SensitiveParameter]
$dbpassword,
$dbname,
$dbhost
) {
if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
$this->show_errors();
}

View File

@@ -938,7 +938,16 @@ function wpmu_signup_user( $user, $user_email, $meta = array() ) {
* @param array $meta Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
* @return bool
*/
function wpmu_signup_blog_notification( $domain, $path, $title, $user_login, $user_email, $key, $meta = array() ) {
function wpmu_signup_blog_notification(
$domain,
$path,
$title,
$user_login,
$user_email,
#[\SensitiveParameter]
$key,
$meta = array()
) {
/**
* Filters whether to bypass the new site email notification.
*
@@ -1073,7 +1082,13 @@ function wpmu_signup_blog_notification( $domain, $path, $title, $user_login, $us
* @param array $meta Optional. Signup meta data. Default empty array.
* @return bool
*/
function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta = array() ) {
function wpmu_signup_user_notification(
$user_login,
$user_email,
#[\SensitiveParameter]
$key,
$meta = array()
) {
/**
* Filters whether to bypass the email notification for new user sign-up.
*
@@ -1175,7 +1190,10 @@ function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta =
* @param string $key The activation key provided to the user.
* @return array|WP_Error An array containing information about the activated user and/or blog.
*/
function wpmu_activate_signup( $key ) {
function wpmu_activate_signup(
#[\SensitiveParameter]
$key
) {
global $wpdb;
$signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = %s", $key ) );
@@ -1327,7 +1345,12 @@ function wp_delete_signup_on_user_delete( $id, $reassign, $user ) {
* @param string $email The new user's email address.
* @return int|false Returns false on failure, or int $user_id on success.
*/
function wpmu_create_user( $user_name, $password, $email ) {
function wpmu_create_user(
$user_name,
#[\SensitiveParameter]
$password,
$email
) {
$user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
$user_id = wp_create_user( $user_name, $password, $email );
@@ -1611,7 +1634,14 @@ function domain_exists( $domain, $path, $network_id = 1 ) {
* @param array $meta Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
* @return bool Whether the email notification was sent.
*/
function wpmu_welcome_notification( $blog_id, $user_id, $password, $title, $meta = array() ) {
function wpmu_welcome_notification(
$blog_id,
$user_id,
#[\SensitiveParameter]
$password,
$title,
$meta = array()
) {
$current_network = get_network();
/**
@@ -1845,7 +1875,12 @@ Name: %3$s'
* @param array $meta Optional. Signup meta data. Default empty array.
* @return bool
*/
function wpmu_welcome_user_notification( $user_id, $password, $meta = array() ) {
function wpmu_welcome_user_notification(
$user_id,
#[\SensitiveParameter]
$password,
$meta = array()
) {
$current_network = get_network();
/**
@@ -2271,7 +2306,12 @@ function add_existing_user_to_blog( $details = false ) {
* @param string $password User password. Ignored.
* @param array $meta Signup meta data.
*/
function add_new_user_to_blog( $user_id, $password, $meta ) {
function add_new_user_to_blog(
$user_id,
#[\SensitiveParameter]
$password,
$meta
) {
if ( ! empty( $meta['add_to_blog'] ) ) {
$blog_id = $meta['add_to_blog'];
$role = $meta['new_role'];

View File

@@ -101,7 +101,15 @@ if ( !function_exists('wp_setcookie') ) :
* @param string $siteurl Optional. Will be used instead of SITECOOKIEPATH if set
* @param bool $remember Optional. Remember that the user is logged in
*/
function wp_setcookie($username, $password = '', $already_md5 = false, $home = '', $siteurl = '', $remember = false) {
function wp_setcookie(
$username,
#[\SensitiveParameter]
$password = '',
$already_md5 = false,
$home = '',
$siteurl = '',
$remember = false
) {
_deprecated_function( __FUNCTION__, '2.5.0', 'wp_set_auth_cookie()' );
$user = get_user_by('login', $username);
wp_set_auth_cookie($user->ID, $remember);
@@ -168,7 +176,12 @@ if ( !function_exists('wp_login') ) :
* @param string $deprecated Not used
* @return bool True on successful check, false on login failure.
*/
function wp_login($username, $password, $deprecated = '') {
function wp_login(
$username,
#[\SensitiveParameter]
$password,
$deprecated = ''
) {
_deprecated_function( __FUNCTION__, '2.5.0', 'wp_signon()' );
global $error;

View File

@@ -598,7 +598,11 @@ if ( ! function_exists( 'wp_authenticate' ) ) :
* @return WP_User|WP_Error WP_User object if the credentials are valid,
* otherwise WP_Error.
*/
function wp_authenticate( $username, $password ) {
function wp_authenticate(
$username,
#[\SensitiveParameter]
$password
) {
$username = sanitize_user( $username );
$password = trim( $password );
@@ -2631,7 +2635,10 @@ if ( ! function_exists( 'wp_hash_password' ) ) :
* @param string $password Plain text user password to hash.
* @return string The hash string of the password.
*/
function wp_hash_password( $password ) {
function wp_hash_password(
#[\SensitiveParameter]
$password
) {
global $wp_hasher;
if ( empty( $wp_hasher ) ) {
@@ -2667,7 +2674,12 @@ if ( ! function_exists( 'wp_check_password' ) ) :
* @param string|int $user_id Optional. User ID.
* @return bool False, if the $password does not match the hashed password.
*/
function wp_check_password( $password, $hash, $user_id = '' ) {
function wp_check_password(
#[\SensitiveParameter]
$password,
$hash,
$user_id = ''
) {
global $wp_hasher;
// If the hash is still md5...
@@ -2863,7 +2875,11 @@ if ( ! function_exists( 'wp_set_password' ) ) :
* @param string $password The plaintext new user password.
* @param int $user_id User ID.
*/
function wp_set_password( $password, $user_id ) {
function wp_set_password(
#[\SensitiveParameter]
$password,
$user_id
) {
global $wpdb;
$old_user_data = get_userdata( $user_id );

View File

@@ -1310,7 +1310,12 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
* @param string $param The parameter name.
* @return string|WP_Error The sanitized password, if valid, otherwise an error.
*/
public function check_user_password( $value, $request, $param ) {
public function check_user_password(
#[\SensitiveParameter]
$value,
$request,
$param
) {
$password = (string) $value;
if ( empty( $password ) ) {

View File

@@ -150,7 +150,12 @@ function wp_signon( $credentials = array(), $secure_cookie = '' ) {
* @param string $password Password for authentication.
* @return WP_User|WP_Error WP_User on success, WP_Error on failure.
*/
function wp_authenticate_username_password( $user, $username, $password ) {
function wp_authenticate_username_password(
$user,
$username,
#[\SensitiveParameter]
$password
) {
if ( $user instanceof WP_User ) {
return $user;
}
@@ -228,7 +233,12 @@ function wp_authenticate_username_password( $user, $username, $password ) {
* @param string $password Password for authentication.
* @return WP_User|WP_Error WP_User on success, WP_Error on failure.
*/
function wp_authenticate_email_password( $user, $email, $password ) {
function wp_authenticate_email_password(
$user,
$email,
#[\SensitiveParameter]
$password
) {
if ( $user instanceof WP_User ) {
return $user;
}
@@ -301,7 +311,12 @@ function wp_authenticate_email_password( $user, $email, $password ) {
* @param string $password Password. If not empty, cancels the cookie authentication.
* @return WP_User|WP_Error WP_User on success, WP_Error on failure.
*/
function wp_authenticate_cookie( $user, $username, $password ) {
function wp_authenticate_cookie(
$user,
$username,
#[\SensitiveParameter]
$password
) {
global $auth_secure_cookie;
if ( $user instanceof WP_User ) {
@@ -342,7 +357,12 @@ function wp_authenticate_cookie( $user, $username, $password ) {
* @return WP_User|WP_Error|null WP_User on success, WP_Error on failure, null if
* null is passed in and this isn't an API request.
*/
function wp_authenticate_application_password( $input_user, $username, $password ) {
function wp_authenticate_application_password(
$input_user,
$username,
#[\SensitiveParameter]
$password
) {
if ( $input_user instanceof WP_User ) {
return $input_user;
}
@@ -2846,7 +2866,12 @@ All at ###SITENAME###
* @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
* be created.
*/
function wp_create_user( $username, $password, $email = '' ) {
function wp_create_user(
$username,
#[\SensitiveParameter]
$password,
$email = ''
) {
$user_login = wp_slash( $username );
$user_email = wp_slash( $email );
$user_pass = $password;
@@ -3034,7 +3059,11 @@ function get_password_reset_key( $user ) {
* @param string $login The user login.
* @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
*/
function check_password_reset_key( $key, $login ) {
function check_password_reset_key(
#[\SensitiveParameter]
$key,
$login
) {
global $wp_hasher;
$key = preg_replace( '/[^a-z0-9]/i', '', $key );
@@ -3371,7 +3400,11 @@ function retrieve_password( $user_login = '' ) {
* @param WP_User $user The user
* @param string $new_pass New password for the user in plaintext
*/
function reset_password( $user, $new_pass ) {
function reset_password(
$user,
#[\SensitiveParameter]
$new_pass
) {
/**
* Fires before the user's password is reset.
*
@@ -4932,7 +4965,11 @@ function wp_generate_user_request_key( $request_id ) {
* @param string $key Provided key to validate.
* @return true|WP_Error True on success, WP_Error on failure.
*/
function wp_validate_user_request_key( $request_id, $key ) {
function wp_validate_user_request_key(
$request_id,
#[\SensitiveParameter]
$key
) {
global $wp_hasher;
$request_id = absint( $request_id );

View File

@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.8-alpha-59753';
$wp_version = '6.8-alpha-59754';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.