I captured one valid PayPal callback and sent it to XenForo twice. Both requests returned success. The same transaction appeared twice in the payment log, and the recurring upgrade was extended twice.
Where the duplicate check went
XenForo’s base payment code checks whether a provider transaction has already been processed. The PayPal REST override of validateTransaction() bypassed that implementation, and the database allowed duplicate transaction IDs.
After signature verification succeeded, XenForo ran purchase completion before any processed-event lookup.
The test used an authentic delivery with its original body and headers:
- Send the callback once and record the new expiry date.
- Replay the exact request.
- Compare the payment log and expiry date again.
Replaying the purchase-completion path required one authentic callback with its original signature.
The public PoC accepts a saved callback and replays it twice. XenForo added replay protection in 2.3.13.