Skip to content

v1.6.1 — Security Release: Payment-State Gate on Manual Order Completion

Choose a tag to compare

@codermillat codermillat released this 04 Sep 04:57
· 5 commits to main since this release

Security release — upgrade recommended for all stores

What was fixed

WooCommerce automatically records any order moved to completed as paid. RouteMile's manual transition paths allowed that to happen with no real payment:

  • Manager path: the deliveries dashboard accepted a transition to completed for unpaid orders — one form POST (with a valid dashboard nonce) turned a pending order into paid=1.
  • Rider path (more serious): an assigned delivery rider could tap Mark Picked Up → Mark Delivered on a prepaid order (bank transfer / cheque) and the order became completed paid=1 with an empty transaction ID — no manager involvement, no gateway call.

Both were reproduced end-to-end in a local penetration test before the fix, and the fix was verified by replaying the exact attacks (now rejected) plus the legitimate flows (now still working).

The fix

All four manual transition endpoints (manager admin-post + AJAX, rider admin-post + AJAX) now call ROUTEW_Order_Lifecycle::can_complete_order(), which refuses the completed transition while the order still needs payment. Unaffected by design:

  • gateway-paid orders (is_paid / date_paid set by the real payment webhook),
  • cash-on-delivery orders where the rider confirmed cash collection (that confirmation already sets date_paid),
  • zero-total orders.

Also in this release

  • New PG1 regression suite (8 tests): pins the gate, all four call sites, the legitimate COD pick-up → cash → deliver sequence, and a future-proof scan that fails the build if any new action can set completed on an unpaid order without the gate.
  • Full audit of the checkout REST endpoints for cross-origin CSRF: confirmed not exploitable in practice (WooCommerce's session cookie never rides a cross-site POST; a live cross-origin browser experiment left the victim's session and cart untouched). No behaviour change needed.

Quality: test suite now 311 checks — WordPress Plugin Check: 0 errors, 0 warnings on the shipped zip. Requires WP 6.0+, PHP 7.4+, WooCommerce 7.0+.

Install: download routemile-woocommerce.1.6.1.zip below and upload via Plugins → Add New → Upload Plugin (or update in-place from 1.6.0 — no settings migration needed).