From 1a449d75d1d0ff1cd678f0ed052242b5c7d97592 Mon Sep 17 00:00:00 2001 From: latenighthackathon Date: Thu, 2 Apr 2026 23:35:42 -0500 Subject: [PATCH 1/2] fix[faustwp]: (#2310, #2311) use hash_equals for secret key comparison, clean up failed blockset extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace timing-vulnerable === comparisons with hash_equals() for the shared secret key in rest_authorize_permission_callback(), wpac_authorize_permission_callback(), and filter_introspection(). The codebase already uses hash_equals() for HMAC validation in auth/functions.php — these three spots were missed. Also sanitize the $_SERVER['HTTP_X_FAUST_SECRET'] superglobal with wp_unslash() and sanitize_text_field() per WordPress coding standards before passing to hash_equals(). Additionally, delete the uploaded blockset file from the target directory when unzip_uploaded_file() fails, preventing orphaned files from accumulating on disk after failed uploads. Closes #2310 Closes #2311 --- plugins/faustwp/includes/blocks/functions.php | 1 + plugins/faustwp/includes/graphql/callbacks.php | 5 +++-- plugins/faustwp/includes/rest/callbacks.php | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) 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; From 2294d333d182ca1f35e9ab8c96f68c8b5f774dc8 Mon Sep 17 00:00:00 2001 From: latenighthackathon Date: Thu, 2 Apr 2026 23:45:04 -0500 Subject: [PATCH 2/2] chore: add changeset for faustwp security hardening --- .changeset/security-hardening-faustwp.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/security-hardening-faustwp.md 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