From 5a3b0e9034f3d6f22db66498af540ee4e1b180b8 Mon Sep 17 00:00:00 2001 From: Boro Sitnikovski Date: Tue, 18 Aug 2026 13:29:55 +0200 Subject: [PATCH 1/4] Slack: Stop unauthenticated requests from fataling the remaining webhook endpoints. hash_equals() requires string arguments in PHP 8. A request with an array-valued secret/token param (e.g. ?secret[]=x) bypassed the empty()/?? guards and fatally errored instead of being rejected, the same class of bug already fixed in announce.php and committers.php. Co-Authored-By: Claude Sonnet 5 --- .../dotorg/slack/community-deputies-calendly-webhook.php | 2 +- api.wordpress.org/public_html/dotorg/slack/trac-bot.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php b/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php index cb4a7b7e38..b62f1f025e 100644 --- a/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php +++ b/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php @@ -49,7 +49,7 @@ function api_request( $url ) { } // Check the request is valid. -if ( empty( $_GET['secret'] ) || ! hash_equals( COMMUNITY_CALENDLY_SECRET, $_GET['secret'] ) ) { +if ( empty( $_GET['secret'] ) || ! is_string( $_GET['secret'] ) || ! hash_equals( COMMUNITY_CALENDLY_SECRET, $_GET['secret'] ) ) { header( 'HTTP/1.1 403 Forbidden' ); die( 'Invalid secret provided.' ); } diff --git a/api.wordpress.org/public_html/dotorg/slack/trac-bot.php b/api.wordpress.org/public_html/dotorg/slack/trac-bot.php index 7eb0cd19db..c7aae61cb5 100644 --- a/api.wordpress.org/public_html/dotorg/slack/trac-bot.php +++ b/api.wordpress.org/public_html/dotorg/slack/trac-bot.php @@ -11,7 +11,7 @@ namespace Dotorg\Slack\Trac { // Verify it came from Slack. - if ( ! hash_equals( URL_SECRET__TRAC_BOT, $_GET['token'] ?? '' ) ) { + if ( ! isset( $_GET['token'] ) || ! is_string( $_GET['token'] ) || ! hash_equals( URL_SECRET__TRAC_BOT, $_GET['token'] ) ) { return; } From fcc3ce91169c299550478e6becd06ce9f5792ed8 Mon Sep 17 00:00:00 2001 From: Boro Sitnikovski Date: Tue, 18 Aug 2026 13:32:26 +0200 Subject: [PATCH 2/4] Slack: Unslash $_GET secret/token before comparison to satisfy WPCS. Co-Authored-By: Claude Sonnet 5 --- .../dotorg/slack/community-deputies-calendly-webhook.php | 2 +- api.wordpress.org/public_html/dotorg/slack/trac-bot.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php b/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php index b62f1f025e..e90dacf17e 100644 --- a/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php +++ b/api.wordpress.org/public_html/dotorg/slack/community-deputies-calendly-webhook.php @@ -49,7 +49,7 @@ function api_request( $url ) { } // Check the request is valid. -if ( empty( $_GET['secret'] ) || ! is_string( $_GET['secret'] ) || ! hash_equals( COMMUNITY_CALENDLY_SECRET, $_GET['secret'] ) ) { +if ( empty( $_GET['secret'] ) || ! is_string( $_GET['secret'] ) || ! hash_equals( COMMUNITY_CALENDLY_SECRET, wp_unslash( $_GET['secret'] ) ) ) { header( 'HTTP/1.1 403 Forbidden' ); die( 'Invalid secret provided.' ); } diff --git a/api.wordpress.org/public_html/dotorg/slack/trac-bot.php b/api.wordpress.org/public_html/dotorg/slack/trac-bot.php index c7aae61cb5..3d9360089f 100644 --- a/api.wordpress.org/public_html/dotorg/slack/trac-bot.php +++ b/api.wordpress.org/public_html/dotorg/slack/trac-bot.php @@ -11,7 +11,7 @@ namespace Dotorg\Slack\Trac { // Verify it came from Slack. - if ( ! isset( $_GET['token'] ) || ! is_string( $_GET['token'] ) || ! hash_equals( URL_SECRET__TRAC_BOT, $_GET['token'] ) ) { + if ( ! isset( $_GET['token'] ) || ! is_string( $_GET['token'] ) || ! hash_equals( URL_SECRET__TRAC_BOT, wp_unslash( $_GET['token'] ) ) ) { return; } From eb8b3ee4e4fa4892831caef5157c457894c89754 Mon Sep 17 00:00:00 2001 From: Konstantin Obenland Date: Tue, 18 Aug 2026 09:55:08 -0700 Subject: [PATCH 3/4] Slack: Stop the security-team endpoint from fataling on an array token. security-team.php passes $_GET['token'] straight to hash_equals(), which fatals on a non-string in PHP 8. The dispatcher gates on the request URI containing '/security-team.php?token=', but '?token=a&token[]=x' satisfies that check while PHP overwrites the value with an array, so the endpoint still throws the same TypeError the rest of this branch fixes. Guard the token the way announce.php and committers.php do. This file only loads hyperdb, so the request is never slashed and the comparison stays on the raw value, with the WPCS unslash sniff annotated accordingly. Also split the inlined guard in trac-bot.php into the same shape, so all four webhook endpoints read alike. No behaviour change there. Co-Authored-By: Claude Opus 5 (1M context) --- .../public_html/dotorg/slack/security-team.php | 8 +++++++- api.wordpress.org/public_html/dotorg/slack/trac-bot.php | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/api.wordpress.org/public_html/dotorg/slack/security-team.php b/api.wordpress.org/public_html/dotorg/slack/security-team.php index 65ce43cf57..ae4112d372 100644 --- a/api.wordpress.org/public_html/dotorg/slack/security-team.php +++ b/api.wordpress.org/public_html/dotorg/slack/security-team.php @@ -61,8 +61,14 @@ function get_security_team( $user_field = 'user_login' ) { function api_call() { header( 'Content-type: text/plain' ); + // Trac sends the token as a query arg; anything else is not a valid request. + if ( ! isset( $_GET['token'] ) || ! is_string( $_GET['token'] ) || '' === $_GET['token'] ) { + exit; + } + // Confirm it came from the Trac server. - if ( ! hash_equals( API_TOKEN, $_GET['token'] ?? '' ) ) { + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- No WP loaded, so the request is never slashed. + if ( ! hash_equals( API_TOKEN, $_GET['token'] ) ) { exit; } diff --git a/api.wordpress.org/public_html/dotorg/slack/trac-bot.php b/api.wordpress.org/public_html/dotorg/slack/trac-bot.php index 3d9360089f..de04f64afc 100644 --- a/api.wordpress.org/public_html/dotorg/slack/trac-bot.php +++ b/api.wordpress.org/public_html/dotorg/slack/trac-bot.php @@ -10,8 +10,13 @@ namespace Dotorg\Slack\Trac { + // Slack sends the token as a query arg; anything else is not a webhook request. + if ( ! isset( $_GET['token'] ) || ! is_string( $_GET['token'] ) || '' === $_GET['token'] ) { + return; + } + // Verify it came from Slack. - if ( ! isset( $_GET['token'] ) || ! is_string( $_GET['token'] ) || ! hash_equals( URL_SECRET__TRAC_BOT, wp_unslash( $_GET['token'] ) ) ) { + if ( ! hash_equals( URL_SECRET__TRAC_BOT, wp_unslash( $_GET['token'] ) ) ) { return; } From efde6d21a555f65b18d570bba71555f3ca605c57 Mon Sep 17 00:00:00 2001 From: Konstantin Obenland Date: Tue, 18 Aug 2026 09:57:52 -0700 Subject: [PATCH 4/4] Slack: Document the sniffs security-team.php cannot satisfy. The linter checks changed lines, and this file keeps its whole body flat inside a curly-brace namespace, so the scope sniff reads every line as one level short. That makes any edit inside the namespace fail regardless of what it does, which is what the guard added in the previous commit ran into. Give the file the header committers.php already carries: the reasons the scope, nonce and unslash sniffs do not apply to a standalone server-to-server endpoint, and a phpcs:disable for each. The inline unslash annotation is now redundant, so drop it. Reindenting all 93 lines would fix the scope sniff for real, but that belongs in its own change, not a crash fix. Co-Authored-By: Claude Opus 5 (1M context) --- .../public_html/dotorg/slack/security-team.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/api.wordpress.org/public_html/dotorg/slack/security-team.php b/api.wordpress.org/public_html/dotorg/slack/security-team.php index ae4112d372..c71b5d4f81 100644 --- a/api.wordpress.org/public_html/dotorg/slack/security-team.php +++ b/api.wordpress.org/public_html/dotorg/slack/security-team.php @@ -1,4 +1,18 @@