Skip to content

SNAPWOO-101 Purchase pixel exposes order and hashed billing data on unauthenticated order-received requests - #89

Open
zamanq wants to merge 2 commits into
developfrom
fix/SNAPWOO-101-purchase-pixel-exposes-order
Open

SNAPWOO-101 Purchase pixel exposes order and hashed billing data on unauthenticated order-received requests#89
zamanq wants to merge 2 commits into
developfrom
fix/SNAPWOO-101-purchase-pixel-exposes-order

Conversation

@zamanq

@zamanq zamanq commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Changes proposed in this Pull Request:

The Snapchat purchase pixel loaded the order straight from the numeric order-received endpoint, without checking the WooCommerce order key. WooCommerce renders a generic confirmation page when the key is missing or wrong, but the pixel handler still added a PURCHASE event to the footer - exposing order total, currency, product IDs, categories, item count and transaction ID, plus SHA-256 hashed billing email/phone/name/city/postcode/country when PII collection is on. Anyone who guessed an order number could read all of that from the page source, no login required.

This PR adds Helper::get_verified_order_received_order(), a single gate that returns the current order-received order only when the request is authorized, mirroring what WooCommerce itself checks before rendering order details:

  • the endpoint resolves to a real WC_Order
  • ?key= is present and passes key_is_valid() (a malformed/array key is rejected without a PHP warning)
  • for orders owned by a registered customer, that customer is the logged-in user

RemotePixelTracker::track_purchase_event() now uses that gate and bails before building any payload and before writing the _snapchat_pixel_tracked meta, so a blocked request leaves the order untracked and the real customer still gets their event.

UserIdentifier::add_user_details() was independently loading the order from the query var, so it leaked hashed billing identifiers on its own. It now accepts an optional WC_Order (the pixel tracker passes the already-verified one) and otherwise falls back to the same gate. This also covers the CAPI user_data path.

Closes https://linear.app/a8c/issue/SNAPWOO-101/purchase-pixel-exposes-order-and-hashed-billing-data-on

Screenshots:

N/A

Detailed test instructions:

  1. Enable Pixel tracking and PII collection, and place a guest order on a test store.
  2. Clear the tracked flag so the pixel is eligible to fire: wp eval '$o = wc_get_order( 123 ); $o->delete_meta_data( "_snapchat_pixel_tracked" ); $o->save();'
  3. Logged out, visit /checkout/order-received/123/ (no key) and also try a wrong key (?key=wc_order_bogus) and a malformed one (?key[]=x). In each case the page source must contain no snaptr("track", "purchase" payload and no hashed identifiers, and the generic confirmation page must render without any errors.
  4. Now open the same order with its valid key (the URL from the order email). The purchase event fires with price, currency, transaction_id, item_ids, item_category, number_items and the hashed billing fields.
  5. Reload that URL - no second purchase event.
  6. Complete a normal checkout as a logged-in customer and confirm exactly one purchase event on the confirmation page.

@github-actions github-actions Bot added the status: e2e tests passing E2E tests are passing on the PR label Aug 19, 2026
@zamanq
zamanq marked this pull request as ready for review August 19, 2026 17:53
@zamanq
zamanq requested a review from jamesmorrison August 19, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: e2e tests passing E2E tests are passing on the PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant