Skip to content

Added WooCommerce request verification token#1253

Merged
vytisbulkevicius merged 3 commits intodevelopmentfrom
bugfix/pro/520
Mar 3, 2026
Merged

Added WooCommerce request verification token#1253
vytisbulkevicius merged 3 commits intodevelopmentfrom
bugfix/pro/520

Conversation

@girishpanchal30
Copy link
Contributor

Summary

This PR secures internal WooCommerce report requests by sending a custom secret header with wp_remote_request() and validating it inside woocommerce_rest_check_permissions, allowing only verified internal AJAX calls while keeping direct public access blocked.

Check before Pull Request is ready:

Closes https://github.com/Codeinwp/visualizer-pro/issues/520

@girishpanchal30 girishpanchal30 requested a review from Copilot March 2, 2026 08:40
@girishpanchal30 girishpanchal30 added the pr-checklist-skip Allow this Pull Request to skip checklist. label Mar 2, 2026
@pirate-bot pirate-bot added the pr-checklist-complete The Pull Request checklist is complete. (automatic label) label Mar 2, 2026
@pirate-bot
Copy link
Contributor

pirate-bot commented Mar 2, 2026

Plugin build for 59e2aef is ready 🛎️!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to secure internal WooCommerce report requests by adding a per-request verification token header to outgoing wp_remote_request() calls from the JSON source, intended to be validated server-side to distinguish internal calls from direct public access.

Changes:

  • Adds generation/storage of a short-lived token (transient) and sends it via X-Visualizer-Token on detected WooCommerce requests.
  • Introduces is_woocommerce_request() helper to identify WooCommerce-related URLs via simple pattern matching.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +460 to +469
// Check if this is a WooCommerce endpoint request and add verification token.
if ( $this->is_woocommerce_request( $url ) ) {
// Generate a unique token for this specific request.
$token = wp_generate_password( 32, false );
set_transient( 'visualizer_wc_token_' . $token, time(), 60 );
if ( ! isset( $args['headers'] ) ) {
$args['headers'] = array();
}
$args['headers']['X-Visualizer-Token'] = $token;
}
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New security behavior (token generation/transient storage + conditional header injection) isn’t covered by the existing PHPUnit tests. Add a unit test that stubs HTTP via pre_http_request to assert the header is (or is not) set for WooCommerce URLs, and that the transient lifecycle behaves as expected.

Copilot uses AI. Check for mistakes.
Comment on lines +460 to +468
// Check if this is a WooCommerce endpoint request and add verification token.
if ( $this->is_woocommerce_request( $url ) ) {
// Generate a unique token for this specific request.
$token = wp_generate_password( 32, false );
set_transient( 'visualizer_wc_token_' . $token, time(), 60 );
if ( ! isset( $args['headers'] ) ) {
$args['headers'] = array();
}
$args['headers']['X-Visualizer-Token'] = $token;
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says the token is validated (e.g., via woocommerce_rest_check_permissions), but in this repo the token is only generated/stored and sent; there is no code that reads X-Visualizer-Token or checks/deletes the corresponding transient. As-is, this doesn’t provide any additional protection and leaves behind short-lived transients on every matched request. Add server-side verification on REST requests (read the header, get_transient()/delete_transient() for single-use, and reject when missing/invalid).

Copilot uses AI. Check for mistakes.
$args['headers']['X-Visualizer-Token'] = $token;
}

do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Connecting to %s with args = %s ', $url, print_r( $args, true ) ), 'debug', __FILE__, __LINE__ );
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

themeisle_log_event logs print_r( $args, true ). With this change, the log payload will include the newly generated X-Visualizer-Token header, which makes the token retrievable from logs during its validity window. Consider redacting this header (and other sensitive headers) from the logged args or skipping verbose logging for these internal WooCommerce requests.

Suggested change
do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Connecting to %s with args = %s ', $url, print_r( $args, true ) ), 'debug', __FILE__, __LINE__ );
// Avoid logging sensitive headers such as X-Visualizer-Token.
$log_args = $args;
if ( isset( $log_args['headers'] ) && is_array( $log_args['headers'] ) ) {
unset( $log_args['headers']['X-Visualizer-Token'] );
}
do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Connecting to %s with args = %s ', $url, print_r( $log_args, true ) ), 'debug', __FILE__, __LINE__ );

Copilot uses AI. Check for mistakes.
}

do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Connecting to %s with args = %s ', $url, print_r( $args, true ) ), 'debug', __FILE__, __LINE__ );
return wp_remote_request( $url, $args );
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code performs a server-side HTTP request to a user-controlled URL using wp_remote_request with no host or protocol restrictions. An authenticated attacker who can reach the JSON import AJAX endpoints (e.g. via visualizer-json-get-roots / visualizer-json-get-data) can supply an arbitrary URL (including internal hosts like http://127.0.0.1/ or cloud metadata IPs), turning this into an SSRF primitive that can probe internal services and, when the response is JSON, exfiltrate data via the chart preview. To mitigate, validate and restrict $_args['url']/$this->_url to an allowlist of expected domains or at minimum block private/reserved IP ranges and non-HTTP(S) schemes before calling wp_remote_request.

Copilot uses AI. Check for mistakes.
@vytisbulkevicius vytisbulkevicius merged commit fdb1511 into development Mar 3, 2026
6 of 8 checks passed
@vytisbulkevicius vytisbulkevicius deleted the bugfix/pro/520 branch March 3, 2026 15:34
@pirate-bot
Copy link
Contributor

🎉 This PR is included in version 3.11.15 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@pirate-bot pirate-bot added the released Indicate that an issue has been resolved and released in a particular version of the product. label Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-checklist-complete The Pull Request checklist is complete. (automatic label) pr-checklist-skip Allow this Pull Request to skip checklist. released Indicate that an issue has been resolved and released in a particular version of the product.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants