Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions .github/workflows/change-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ concurrency:
jobs:
generate-wc-compat-matrix:
name: "Generate the matrix for woocommerce compatibility dynamically"
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate_matrix.outputs.matrix }}
steps:
Expand All @@ -33,7 +33,7 @@ jobs:
woocommerce-compatibility:
name: "WC compatibility"
needs: generate-wc-compat-matrix
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
WP_VERSION: ${{ matrix.wordpress }}
WC_VERSION: ${{ matrix.woocommerce }}
Expand All @@ -44,9 +44,9 @@ jobs:
matrix: ${{ fromJSON(needs.generate-wc-compat-matrix.outputs.matrix) }}
steps:
# clone the repository
- uses: actions/checkout@v3
- uses: actions/checkout@v5
# enable dependencies caching
- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: ~/.cache/composer/
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
Expand All @@ -56,19 +56,21 @@ jobs:
php-version: ${{ matrix.php }}
tools: composer
coverage: xdebug
- name: Install Subversion
run: sudo apt-get update && sudo apt-get install -y subversion
# run CI checks
- run: bash bin/run-ci-tests.bash
# report to codecov
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODE_COV_TOKEN }}
files: ./coverage.xml
verbose: true

generate-wc-compat-beta-matrix:
name: "Generate the matrix for compatibility-woocommerce-beta dynamically"
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate_matrix.outputs.matrix }}
steps:
Expand All @@ -82,7 +84,7 @@ jobs:
compatibility-woocommerce-beta:
name: Environment - WC beta
needs: generate-wc-compat-beta-matrix
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.generate-wc-compat-beta-matrix.outputs.matrix) }}
Expand All @@ -92,9 +94,9 @@ jobs:
GUTENBERG_VERSION: ${{ matrix.gutenberg }}
steps:
# clone the repository
- uses: actions/checkout@v3
- uses: actions/checkout@v5
# enable dependencies caching
- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: ~/.cache/composer/
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
Expand All @@ -104,6 +106,9 @@ jobs:
php-version: ${{ matrix.php }}
tools: composer
coverage: none

- name: Install Subversion
run: sudo apt-get update && sudo apt-get install -y subversion
# Check if php version is greater than 8.0 and install phpunit 9
- uses: ./.github/actions/check-php-version-phpunit-support
with:
Expand All @@ -120,7 +125,7 @@ jobs:
runs-on: ${{ matrix.operating-system }}
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v5
- name: "Validate composer.json and composer.lock"
run: composer validate --strict
- name: Setup PHP
Expand All @@ -131,7 +136,7 @@ jobs:
coverage: none
tools: cs2pr
- name: Install Composer dependencies
uses: "ramsey/composer-install@v2"
uses: "ramsey/composer-install@v3"
- name: Run PHPCS checks
continue-on-error: true
run: vendor/bin/phpcs --ignore=*/tests/*,*/data/*,*/assets/* --report-full --report-checkstyle=./phpcs-report.xml
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/package-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
status: starting
if: ${{ always() }}
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v5
- name: Setup Node.js environment
uses: actions/setup-node@v2.5.2
uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
- name: Build Plugin
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/security-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
OS: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v2
uses: actions/checkout@v5

- name: Checkmarx One ClI Action
uses: checkmarx/ast-github-action@main
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.18.0
24.20.0
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
# Changelog
## 3.3.1 | 08-09-2026
Security release.

### Version Changes
- [SECURITY] Authenticate the payment callback (`?wc-api=flw_wc_payment_gateway`) against the order key. The endpoint previously accepted any order ID, so an unauthenticated request could cancel or fail arbitrary pending orders (CWE-288 / CWE-306).
- [SECURITY] Confirm a cancellation with Flutterwave before changing an order. A client-supplied `status=cancelled` no longer moves an order on its own.
- [SECURITY] Bind each callback to a transaction reference this store issued for that order, so a reference from another order cannot be replayed.
- [SECURITY] Ignore callbacks for orders that are no longer awaiting payment, making repeat callbacks inert.
- [SECURITY] Compare the webhook `verif-hash` with `hash_equals()`, and reject webhooks when no secret hash is configured.
- [SECURITY] Reject replayed webhooks by recording the Flutterwave transaction id already processed for an order (CWE-294).
- [SECURITY] Encrypt the stored Flutterwave card token at rest instead of keeping it as plaintext order meta.
- [SECURITY] Stop writing the full webhook body, which contains customer PII, to the WooCommerce log unless logging is explicitly enabled.
- [SECURITY] Scope checkout nonces to the order they belong to rather than validating against the default action.
- [SECURITY] Orders with no recorded transaction reference now only accept a reference issued in that order's name (`WOOC_<order id>_…`), rather than any reference.
- [FIXED] Preserve callback parameters on stores using plain permalinks, where the return URL previously lost them.
- [FIXED] Store order metadata through the CRUD API so transaction references and payment tokens work under HPOS.
- [FIXED] Correct the plugin header, which declared a WooCommerce floor above its own "tested up to" version.
- [FIXED] A successful Flutterwave charge that completes after its order was cancelled now reopens the order (after confirming the charge with Flutterwave) instead of being rejected as "Order already processed", which left customers charged with nothing fulfilled.
- [CHANGED] Update the JavaScript and PHP toolchains; the build now requires Node 24.
- [REMOVED] Unreferenced express-checkout scaffolding (`client/blocks/payment-request/`) and the unused `flutterwave-react-v3`, `gridicons` and `@automattic/interpolate-components` dependencies, which pulled a vulnerable axios into the dependency tree without reaching the build.
## 3.3.0 | 21-07-2026
- [ADDED] Update the signoz service to take traces and spans.
- [ADDED] Support for PHP 8.2 - 8.4
Expand Down
16 changes: 14 additions & 2 deletions assets/js/checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ jQuery( function ( $ ) {
.submit();
};

/**
* Append a query parameter to a URL that may already carry a query string.
*
* The gateway return URL always carries wc-api, order_id and the order key,
* so appending with "?" here would fold those into the previous parameter's
* value and the callback would reject the request.
*/
const withParam = function (url, key, value) {
const separator = url.indexOf('?') === -1 ? '?' : '&';
return url + separator + key + '=' + encodeURIComponent(value);
};

const processData = () => {
return {
public_key: flw_payment_args.public_key,
Expand All @@ -24,7 +36,7 @@ jQuery( function ( $ ) {
$.unblockUI();
if (payment_made) {
$.blockUI({message: '<p> confirming transaction ...</p>'});
redirectPost(flw_payment_args.redirect_url + "?tx_ref=" + flw_payment_args.tx_ref, {});
redirectPost(withParam(flw_payment_args.redirect_url, 'tx_ref', flw_payment_args.tx_ref), {});
} else {
$.blockUI({message: '<p> Canceling Payment ...</p>'});
window.location.href = flw_payment_args.cancel_url;
Expand All @@ -35,7 +47,7 @@ jQuery( function ( $ ) {
if ( 'successful' === response.status ) {
payment_made = true;
$.blockUI({message: '<p> confirming transaction ...</p>'});
redirectPost(flw_payment_args.redirect_url + "?txref=" + tr, response);
redirectPost(withParam(flw_payment_args.redirect_url, 'tx_ref', tr), response);
}
this.close(); // close modal
},
Expand Down
2 changes: 1 addition & 1 deletion assets/js/checkout.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bin/run-ci-tests.bash
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ IFS=$'\n\t'
WOOCOMMERCE_RAVE_DIR="$GITHUB_WORKSPACE"

echo 'Updating composer version & Install dependencies...'
composer self-update 2.0.6 && composer install --no-progress
composer install --no-progress

echo 'Starting MySQL service...'
sudo systemctl start mysql.service
Expand Down
10 changes: 10 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
== Changelog ==
= 3.3.1 =
* Security: Authenticate the payment callback against the order key; it previously accepted any order ID from an unauthenticated request.
* Security: Confirm cancellations with Flutterwave before changing an order status.
* Security: Reject transaction references and webhooks replayed against an order.
* Security: Use a timing-safe comparison for the webhook signature.
* Security: Encrypt the stored card token at rest and keep customer PII out of the logs.
* Security: Orders with no recorded transaction reference only accept a reference issued in that order's name.
* Fixed: Callback parameters are no longer dropped on stores using plain permalinks.
* Fixed: Order metadata is written through the CRUD API so it works under HPOS.
* Fixed: A successful charge that completes after its order was cancelled now reopens the order instead of being rejected, so customers are not left charged with nothing fulfilled.
= 3.1.0 =
* Added: Set Minimum Support to WooCommerce 6.9 or greater.
* Added: Flutterwave Logger instance using wc_logger.
Expand Down
2 changes: 0 additions & 2 deletions client/blocks/payment-request/apple-pay-preview.js

This file was deleted.

76 changes: 0 additions & 76 deletions client/blocks/payment-request/branded-buttons.js

This file was deleted.

2 changes: 0 additions & 2 deletions client/blocks/payment-request/constants.js

This file was deleted.

23 changes: 0 additions & 23 deletions client/blocks/payment-request/custom-button.js

This file was deleted.

Empty file.
24 changes: 0 additions & 24 deletions client/blocks/payment-request/hooks.js

This file was deleted.

26 changes: 0 additions & 26 deletions client/blocks/payment-request/index.js

This file was deleted.

Loading