Make WordPress Core


Ignore:
Timestamp:
11/10/2026 03:23:41 PM (38 hours ago)
Author:
whyisjake
Message:

Security: Require WP_SECRETS_KEY for the Secrets API.

Without WP_SECRETS_KEY, the default keyring derived its key from LOGGED_IN_KEY . LOGGED_IN_SALT. Rotating the salts, which is routine advice, then locked every stored secret. The salts were also read directly rather than through wp_salt(), so an unfilled or translated placeholder from wp-config-sample.php could become the key.

This removes the fallback. Without a usable WP_SECRETS_KEY, every call that needs the key returns secret_key_unavailable. A key is not usable when it is empty or only whitespace, when it is the wp-config-sample.php placeholder, or when it equals any of the authentication keys and salts.

Site Health reports a missing or unusable key as recommended and shows a newly generated define() line to add. It reads the key's state from the new WP_Secrets_Config_Key_Provider::get_key_status() instead of parsing the translated key source.

This also introduces wp_is_secrets_api_available(), so a caller can check before moving a credential into the Secrets API. It returns false when the secrets.php drop-in failed to load, when the default keyring has no usable key, or when the key cannot unwrap the stored root key.

A site that stored secrets under the fallback keeps them. They can be read again once WP_SECRETS_KEY is set to a new key, WP_SECRETS_KEY_PREVIOUS is set to the old LOGGED_IN_KEY . LOGGED_IN_SALT, and the root key is re-wrapped with WP_Secrets_Key_Manager::rotate_site_key().

Follow-up to r64337.

Props ericmann, peterwilsoncc, Clorith, dhrupo, wildworks, johnbillion, jorbin, digitalpritam.
See #66187.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/includes/bootstrap.php

    r65276 r65385  
    3131
    3232/*
    33  * The Secrets API will not derive a key from the placeholder salts that
    34  * wp-tests-config-sample.php ships with, so give the suite a fixed test key.
     33 * The Secrets API needs WP_SECRETS_KEY, which wp-tests-config-sample.php does not
     34 * define, so give the suite a fixed test key.
    3535 *
    3636 * Not in a process-isolated test: PHPUnit sets $GLOBALS['__PHPUNIT_BOOTSTRAP']
    … …  
    3939 * leave it undefined.
    4040 */
    41 if ( ! defined( 'WP_SECRETS_KEY' ) && ! isset( $GLOBALS['__PHPUNIT_BOOTSTRAP'] )
    42         && defined( 'LOGGED_IN_KEY' ) && 'put your unique phrase here' === LOGGED_IN_KEY
    43 ) {
     41if ( ! defined( 'WP_SECRETS_KEY' ) && ! isset( $GLOBALS['__PHPUNIT_BOOTSTRAP'] ) ) {
    4442        define( 'WP_SECRETS_KEY', base64_encode( str_repeat( 'k', 32 ) ) );
    4543}
Note: See TracChangeset for help on using the changeset viewer.