[PM-36079] fix: re-introduce PayPal IPN postback verification#7784
[PM-36079] fix: re-introduce PayPal IPN postback verification#7784connerbw wants to merge 1 commit into
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Re-introduces PayPal IPN postback verification ( Code Review DetailsNo findings. The fail-open semantics on |
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7784 +/- ##
=======================================
Coverage 61.05% 61.05%
=======================================
Files 2173 2173
Lines 96580 96609 +29
Branches 8691 8693 +2
=======================================
+ Hits 58963 58987 +24
- Misses 35516 35521 +5
Partials 2101 2101 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|



🎟️ Tracking
Resolves PM-36079 (originating finding: VULN-550 / HackerOne).
📔 Objective
POST /paypal/ipnpreviously authenticated inbound PayPal IPN messages only with the static?key=query-string secret (plus aReceiverId == BusinessIdcheck, whereBusinessIdis public). The repository shipped a real PayPal postback validator (IPayPalIPNClient.VerifyIPN, thecmd=_notify-validateround-trip), but it was dead code — wired up in #3619 and removed in #3882 because the previous implementation broke constantly and, being fail-closed, dropped legitimate payments.This PR re-introduces postback verification as a defense-in-depth layer, implemented to PayPal's current spec so it no longer regresses payment reliability:
ipnpb.paypal.com/ipnpb.sandbox.paypal.comhost (the legacywww.paypal.com/cgi-bin/webscrredirects and silently drops the POST body).HttpClientnow sends a descriptiveUser-Agent(PayPal returns403without one) and a 10s timeout.VerifyIPNreturns a tri-state result.Invalid(PayPal reports the message is not genuine) blocks processing; a transient failure (Unverified— network error / timeout / non-200) fails open and still processes, so a PayPal-side hiccup can never again drop legitimate credit.FeatureFlagKeys.PM36079_PayPalIpnVerification(default off) for gradual rollout and instant disable without a deploy.A forged /
INVALIDIPN now returns200 OKwithout crediting — this acknowledges PayPal (avoiding retry storms) and gives an attacker no detection oracle. Verification is placed before the credit/refund switch, so both the credit and refund paths are protected.Ops follow-up: alert on the
Unverifiedwarning log line — a sustained spike is the only signature of the fail-open path being exercised.Testing
PayPalIPNClientTests: updated for theipnpbendpoint and tri-state result, including a transient-exception case.PayPalControllerTests: added coverage forINVALIDblocking a payment,INVALIDblocking a refund,Unverifiedstill processing (fail-open),Verifiedprocessing, and the flag-disabled path skipping verification.