Skip to content

Commit 26b9a35

Browse files
committed
fix: harden amount validation to prevent replay attacks
SECURITY: Changed from blind 1-cent exception to absolute difference check. Previous code: if amounts don't match AND amount != 1 cent, reject - Allowed ANY 1-cent payment to complete ANY order (replay attack) New code: if absolute difference > 1 cent, reject - Allows exact matches - Allows 0 EUR order + 1 cent (subscription validation) - Prevents $0.01 payment completing $100 order Applied to both IPN webhook and redirect verification.
1 parent d9d2c41 commit 26b9a35

File tree

2 files changed

+10
-5
lines changed

2 files changed

+10
-5
lines changed

includes/class-wc-monei-ipn.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,13 @@ protected function handle_valid_ipn( $payload ) {
200200
$order_total = $order->get_total();
201201

202202
/**
203-
* If amounts don't match, we mark the order on-hold for manual validation.
204-
* 1 cent exception, for subscriptions when 0 sign ups are done.
203+
* If amounts don't match (within 1 cent tolerance), mark order on-hold for manual validation.
204+
* Absolute difference check allows subscription validation (0 EUR + 1 cent) while preventing
205+
* replay attacks with mismatched amounts.
205206
*/
206-
if ( ( (int) $amount !== monei_price_format( $order_total ) ) && ( 1 !== $amount ) ) {
207+
$expected_amount = monei_price_format( $order_total );
208+
$amount_diff = abs( (int) $amount - $expected_amount );
209+
if ( $amount_diff > 1 ) {
207210
$order->update_status(
208211
'on-hold',
209212
sprintf(

includes/class-wc-monei-redirect-hooks.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,10 @@ private function verify_and_complete_order( $order_id, $payment ) {
217217
$amount = $payment->getAmount();
218218
$order_total = $order->get_total();
219219

220-
// Verify amounts match (with 1 cent exception for subscriptions)
221-
if ( ( (int) $amount !== monei_price_format( $order_total ) ) && ( 1 !== $amount ) ) {
220+
// Verify amounts match (within 1 cent tolerance for subscriptions)
221+
$expected_amount = monei_price_format( $order_total );
222+
$amount_diff = abs( (int) $amount - $expected_amount );
223+
if ( $amount_diff > 1 ) {
222224
$order->update_status(
223225
'on-hold',
224226
sprintf(

0 commit comments

Comments
 (0)