diff --git a/.changeset/security-hardening-faustwp.md b/.changeset/security-hardening-faustwp.md new file mode 100644 index 000000000..60b2b246f --- /dev/null +++ b/.changeset/security-hardening-faustwp.md @@ -0,0 +1,5 @@ +--- +"@faustwp/wordpress-plugin": patch +--- + +fix[faustwp]: use hash_equals() for constant-time secret key comparison in REST and GraphQL permission callbacks, clean up uploaded blockset file on failed extraction diff --git a/plugins/faustwp/includes/blocks/functions.php b/plugins/faustwp/includes/blocks/functions.php index 716e2ff71..8253f4053 100644 --- a/plugins/faustwp/includes/blocks/functions.php +++ b/plugins/faustwp/includes/blocks/functions.php @@ -53,6 +53,7 @@ function process_and_replace_blocks( $wp_filesystem, $file, $dirs ) { $unzip_result = unzip_uploaded_file( $target_file, $dirs['target'] ); if ( is_wp_error( $unzip_result ) ) { + $wp_filesystem->delete( $target_file ); return $unzip_result; } diff --git a/plugins/faustwp/includes/graphql/callbacks.php b/plugins/faustwp/includes/graphql/callbacks.php index 7c0cf1fdc..be3a4956e 100644 --- a/plugins/faustwp/includes/graphql/callbacks.php +++ b/plugins/faustwp/includes/graphql/callbacks.php @@ -66,8 +66,9 @@ function filter_introspection( $value, $default_value, $option_name, $section_fi return $value; } - $secret_key = get_secret_key(); - if ( $secret_key !== $_SERVER['HTTP_X_FAUST_SECRET'] ) { + $secret_key = get_secret_key(); + $faust_secret = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FAUST_SECRET'] ) ); + if ( ! hash_equals( $secret_key, $faust_secret ) ) { return $value; } diff --git a/plugins/faustwp/includes/rest/callbacks.php b/plugins/faustwp/includes/rest/callbacks.php index 7574c025a..fa600ea97 100644 --- a/plugins/faustwp/includes/rest/callbacks.php +++ b/plugins/faustwp/includes/rest/callbacks.php @@ -419,7 +419,7 @@ function rest_authorize_permission_callback( \WP_REST_Request $request ) { $header_key = $request->get_header( 'x-faustwp-secret' ); if ( $secret_key && $header_key ) { - return $secret_key === $header_key; + return hash_equals( $secret_key, $header_key ); } return false; @@ -444,7 +444,7 @@ function wpac_authorize_permission_callback( \WP_REST_Request $request ) { $header_key = $request->get_header( 'x-wpe-headless-secret' ); if ( $secret_key && $header_key ) { - return $secret_key === $header_key; + return hash_equals( $secret_key, $header_key ); } return false;